1.协议分层
- 数据链路层(ARP、RARP)
- 网络层(ICMP、IP)
- 传输层 (TCP、UDP)
- 应用层(PING、telnet、OSPF、DNS)
2. tcp与udp介绍与区别
TCP(Transmission Control Protocol传输控制协议): 是一 种面向连接的、可靠的、基于字节流的传输层通信协议,使用三次握手协议建立连接、四次挥手断开连接。面向连接意味着两个使用TCP的应用(通常是一个
客户端和一 个服务器)在彼此交换数据包之前必须先建立一一个TCP连接。在一一个TCP连接中,仅有两方进行彼此通信,广播和多播不能用TCP。TCP协议的作用是,保证数据通信的完整性和可靠性,防止丢包。TCP把
连接作为最基本的对象,每-条TCP连接都有两个端点, 这种端点我们叫作套接字(socket),端口号拼接到IP地址即构成了套接字。
UDP(User Datagram Protocol用户数据报协议): 是OSI(Open System Interconnection开放式系统互联)参考模型中- -种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。UDP协议的主要作用是将网
络数据流量压缩成数据包的形式。
区别:
- TCP提供的是面向连接的、可靠的数据流传输; UDP提供的是非面向连接的、不可靠的数据流传输。
- TCP提供可靠的服务,通过TCP连接传送的数据,无差错、不丢失、不重复,按序到达; UDP尽最大努力交付,即不保证可靠交付。
- TCP面向字节流; UDP面向报文。
- TCP连接只能是点到点的; UDP支持-对一、一对多 多对一和多对多的交互通信。
- UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
- TCP对系统资源要求较多,UDP对系统资源要求较少。TCP首部有20字节; UDP的首部只有8个字节。
- TCP的逻辑通信信道是全双工的可靠信道; UDP的逻辑通信信道是不可靠信道。
TCP问题之粘包处理
出现的原因:
出现粘包现象的原因是多方面的,它既可能由发送方造成,也可能由接收方造成。发送方引起的粘包是由TCP协议本身造成的, TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据。 若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成包后一次发送出去,这样接收方就收到了粘包数据。
接收方引起的粘包是由于接收方用户进程不及时接收数据,从而导致粘包现象。这是因为接收方先把收到的数据放在系统接收缓冲区,用户进程从该缓冲区取数据,若下一包数据到达时前一包数据尚未被用户进程取
走,则下一包数据放到系统接收缓冲区时就接到前一包数据之后,而用户进程根据预先设定的缓冲区大小从系统接收缓冲区取数据,这样就一次取到了多包数据。
解决方案:
- 特殊字符方式
<?php
// swoole_tcp_client
for ($i=0; $i < 100; $i++) {
$client->send("hello world\i");
}
// swoole_tcp_server
// 监听数据接收事件
$serv->on('Receive', function ($serv, $fd, $from_id, $data) {
// 接收客户端的想你想
var_dump(explode('\i', $data));
// echo "接收到".$fd."信息的".$data."\n";
// echo "接收到".$fd."信息"."\n";
$serv->send($fd, "Server: ");
});
?>
- 统一粘包标准(固定包头+包体协议)
<?php
// client 通过pack进行组包
for ($i=0; $i < 10; $i++) {
// 组包
// msg protocol
// | ---- dataLen ---- | data |
// | - fixed 2bytes - |
$context = "123";
$len = pack("n", strlen($context));
var_dump($len);
$send = $len . $context;
// var_dump($send);
$client->send($send);
}
// server
//监听数据接收事件
$serv->on('Receive', function ($serv, $fd, $from_id, $data){
var_dump($data);
$fooLen = unpack("n", substr($data, $count, 2))[1];
var_dump($fooLen);
$foo = substr($data, $count + 2, $fooLen);
var_dump($foo);
$serv->send($fd, "Server: ");
});
?>