Python网络编程之socket编程(一)–使用TCP和UDP客户端和服务器通信

  • Post author:
  • Post category:python


本文用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有缓冲区,使用它们时该注意什么?




版权声明:本文为FreeeLinux原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。