本文用python进行socket编程,实现客户端和服务器互相发送字符串,并在标准输出打印。
TCP协议版本
下面是客户端程序:
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('192.168.33.5', 6666)
sock.connect(server_address)
message = 'hello,world'
sock.sendall(message)
下面是服务器端程序:
import socket
host = '' //表示任意
port = 6666
s = socket.socket(socket.AF_INET, socket.SOCK_SOCKSTREAM)
s.bind((host, port)) //注意参数为元组
s.listen(5)
conn, addr = s.accept()
while True:
? ? data = conn.recv(3)
? ? print data
? ? if not data:
? ? ? ? break;
? ? #conn.sendall(data)
conn.close()
UDP协议版本
下面是客户端程序:
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ('192.168.33.5', 6666)
#sock.connect(server_address)
message = 'hello,world'
)sock.sendto(message, server_address)
下面是服务端程序:
import socket
host = ''
port = 6666
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((host, port))
while True:
data, (peer_host, peer_port) = s.recvfrom(3)
print data
if not data:
break;
conn.close()
总结
相信从上面的代码你也看出了不少门道,TCP和UDP的区别显而易见了。主要有以下几个特点:
(1)UDP无连接。UDP服务端不需要listen,客户端不需要connect。而TCP需要先由客户端connect发起SYN连接,服务端接收到SYN后,将该连接放入内核等待队列,回复SYN+ACK然后进入SYN_RECEIVED状态,客户端再回复ACK之后,客户端和服务端都进入ESTABLISHED状态。等到accept后将把这个连接取出正式使用。但是UDP没有这个过程。我们发现UDP客户端启动程序,在服务端程序甚至都没有启动的情况下,UDP客户端就完成了自己的工作,什么也不管。而如果是TCP客户端启动,肯定会先connect。如果服务端没有启动,那么绝对会connect refused。
(2)UDP不可靠
在上面的代码中,我刻意限制服务端只接受三个字节,而TCP接受到后,会将收到的TCP报文段放入TCP接收缓冲区,如果应用层缓冲区不够大,不能一次行读取完,可以循环读取。但是,UDP如果 应用层缓冲区不足以容纳整个UDP数据报,那么会出现 截断。另一方面,较快的发送也可能导致 UDP套接口接收缓冲区(内核缓冲区)溢出,导致 丢包。
验证如下图:
1.tcp
2.udp
(3)TCP字节流。上述同样体现了TCP字节流,UDP是数据报的特点。由于应用层缓冲区不够一个UDP报文段的大小,UDP报文段直接被截断了。
补充
UDP套接口有发送缓冲区大小(SO_SNDBUF修改),不过它仅仅是写到套接口的UDP数据报的大小上限。 如果应用程序写一个大于套接口发送缓冲区大小的数据报,内核将返回一个EMSGSIZE错误。 既然UDP不可靠,他不必保存应用进程的数据拷贝,因此无需真正的发送缓冲区(应用进程的数据在沿协议栈往下传递,以某种形式拷贝到内核缓冲区,然而数据链路层在送出数据之后将丢弃该拷贝)。
根据上图发现,UDP没有MSS的概念,如果某个UDP应用程序发送大数据,那么他比TCP应用程序更容易分片。从UDP套接口 write成功返回仅仅表示用户写入的数据报或者所有片段已经加入到数据链路层的输出队列。如果该队列没有足够的空间存放该数据报或者他的某个片段,内核通常返回给应用进程一个ENOBUFS错误(也有的系统不会返回错误)。
TCP和UDP都拥有套接口接收缓冲区。TCP套接口接收缓冲区不可能溢出,因为TCP具有流量控制(窗口).然而对于TCP来说, 当接收到的数据报装不进套接口接收缓冲区时,该数据报就丢弃 。UDP是没有流量控制的:较快的发送端可以很容易淹没较慢的接收端,导致接收端的UDP丢弃数据报。
关于TCP和UDP详情参见:TCP与UDP收发的时候TCP有缓冲区还是UDP有缓冲区,使用它们时该注意什么?。