socket编程

Posted lilong74

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了socket编程相关的知识,希望对你有一定的参考价值。

一、TCP、UDP协议的简单应用

1、使用TCP协的通信的基本格式

技术图片
 1 # 服务端
 2 from socket import *    #导入socket模块
 3 
 4 ip_port = ("127.0.0.1",8080)
 5 back_log = 5                #最大连接数(挂起)
 6 buffer_size = 1024          #最大接受字节
 7 
 8 tcp_server = socket(AF_INET,SOCK_STREAM)    #注意与UDP的区别
 9 tcp_server.bind(ip_port)        #绑定IP地址
10 tcp_server.listen(back_log)     #设置最大监听数(挂起)
11 
12 print("服务端开始运行...")
13 
14 #循环接受链接(未连接)
15 while True:
16     conn,addr = tcp_server.accept()     #接受数据,为一个元组
17     print("双向链接是:",conn)
18     print("客户端地址:",addr)
19 
20     # 循环接受信息(已连接)
21     while True:
22         try:            #防止接受的数据为空(None),导致异常
23             data = conn.recv(buffer_size)
24             if not data:
25                 break
26             print("客户端:\n\t",data.decode("utf-8"))  #解码
27             conn.send(data.upper())
28         except Exception:
29             break             #退出信息循环层
30 
31     conn.close()               #结束与client的连接,等待下一次连接
32 
33 tcp_server.close()
server
技术图片
 1 # 客户端
 2 from socket import *
 3 
 4 ip_port = (127.0.0.1,8080)
 5 back_log = 5
 6 buffer_size = 1024
 7 
 8 tcp_client = socket(AF_INET,SOCK_STREAM)
 9 tcp_client.connect(ip_port)             #连接服务端
10 
11 # 循环接受信息
12 while True:
13     msg = input(">>:")
14     if not msg:         #发送信息为空时
15         continue
16 
17     tcp_client.send(msg.encode("utf-8"))
18     print("客户端已发送消息")
19 
20     data = tcp_client.recv(buffer_size)
21     print("客户端已收到消息",data.decode("utf-8"))
22 
23 tcp_client.close()
client

注意:

  1. 最大连接数指的是,最多可以支持多人挂起,并非同时进行连接
  2. 当client断开连接时,会发生异常,需要做异常处理
  3. 对于TCP协议,当accept接受到的数据为空时,server端会堵塞

2、使用UDP协的通信的基本格式

技术图片
 1 # 服务器
 2 from socket import *
 3 ip_port = ("127.0.0.1",8080)
 4 buffer_size = 1024
 5 
 6 udp_server = socket(AF_INET,SOCK_DGRAM)
 7 udp_server.bind(ip_port)
 8 
 9 print("服务器启动...")
10 
11 while True:
12     data,addr = udp_server.recvfrom(buffer_size)
13     print(data.decode("utf-8"))
14 
15     udp_server.sendto(data.upper(),addr)
server
技术图片
 1 # 客户端
 2 from socket import *
 3 
 4 ip_port = ("127.0.0.1",8080)
 5 buffer_size = 1024
 6 
 7 udp_client = socket(AF_INET,SOCK_DGRAM)
 8 
 9 
10 while True:
11     msg = input(">>:")
12     if not msg:
13         continue
14     udp_client.sendto(msg.encode("utf-8"),ip_port)
15 
16     data,addr = udp_client.recvfrom(buffer_size)
17     print(data.decode("utf-8"))
client

注意:

  1. 使用UDP通信时,并不需要连接,而是在发送数据时,才指定IP地址和端口,所有server接受为空时,并不报错

二、socketserver的使用

利用socketserver达到并发的效果(针对TCP)

技术图片
 1 import socketserver
 2 
 3 class MyServer(socketserver.BaseRequestHandler):    #必须继承这个类
 4     def handle(self):                           #必须重写这个方法
 5         print("conn is:",self.request)
 6         print("addr is:",self.client_address)
 7 
 8         while True:
 9             try:
10                 data = self.request.recv(1024)
11                 print("客户端:\n\t",data)
12 
13                 self.request.sendall(data.upper())
14             except Exception as e:
15                 print(e)
16                 break
17 
18 if __name__ == __main__:
19     s = socketserver.ThreadingTCPServer(("127.0.0.1",8080),MyServer)
20     s.serve_forever()                   #启动
server

client端不变

注意:

  1. 即使,client断开连接,发生异常,server也会继续跟其他client通信
  2. 但是,也具有socket的通行,server接受数据为空时,会发生堵塞

三、粘包的发生

1、发送的多条数据远小于缓存区的大小时间间隔短(为了减少延时,tcp通过算法会把数据合并发送)

技术图片
 1 from socket import *
 2 import time
 3 
 4 ip_port = ("127.0.0.1",8080)
 5 back_log = 5
 6 buffer_size = 1024
 7 
 8 tcp_client = socket(AF_INET,SOCK_STREAM)
 9 tcp_client.connect(ip_port)
10 
11 # 第一种粘包
12 tcp_client.send("Hello".encode("utf-8"))
13 tcp_client.send("world".encode("utf-8"))
14 tcp_client.send("lilong".encode("utf-8"))
server
技术图片
 1 from socket import *
 2 import time
 3 
 4 ip_port = ("127.0.0.1",8080)
 5 back_log = 5
 6 buffer_size = 1024
 7 
 8 tcp_client = socket(AF_INET,SOCK_STREAM)
 9 tcp_client.connect(ip_port)
10 
11 # 第一种粘包
12 tcp_client.send("Hello".encode("utf-8"))
13 
14 time.sleep(1)
15 
16 tcp_client.send("world".encode("utf-8"))
17 
18 time.sleep(1)
19 
20 tcp_client.send("lilong".encode("utf-8"))
client

2、发送的数据大于缓存区的大小

技术图片
 1 from socket import *
 2 
 3 ip_port = ("127.0.0.1",8080)
 4 back_log = 5
 5 buffer_size = 1024
 6 
 7 tcp_server = socket(AF_INET,SOCK_STREAM)
 8 tcp_server.bind(ip_port)
 9 tcp_server.listen(back_log)
10 
11 conn,addr = tcp_server.accept()
12 
13 data1 = conn.recv(5)
14 print("第1个数据",data1.decode("utf-8"))
15 
16 data2 = conn.recv(5)
17 print("第1个数据",data2.decode("utf-8"))
18 
19 data3 = conn.recv(5)
20 print("第1个数据",data3.decode("utf-8"))
server
技术图片
 1 from socket import *
 2 import time
 3 
 4 ip_port = ("127.0.0.1",8080)
 5 back_log = 5
 6 buffer_size = 1024
 7 
 8 tcp_client = socket(AF_INET,SOCK_STREAM)
 9 tcp_client.connect(ip_port)
10 
11 tcp_client.send("Helloworld!lilong".encode("utf-8"))
client

四、粘包的解决方法

1、直接告诉客户端发送数据的字节

server端(核心代码):

1 length = len(data)
2 conn.send(str(length).encode("utf-8"))
3 
4 client_ready = conn.recv(1024)#卡住
5 if client_ready == b"ready":           #同步
6   conn.send(data)

client端(核心代码):

 1 length = tcp_client.recv(buffer_size)
 2     tcp_client.send(b"ready")
 3 
 4     length = int(length.decode("utf-8"))
 5 
 6     recv_size = 0
 7     recv_msg = b""
 8     while recv_size < length:
 9         recv_msg += tcp_client.recv(buffer_size)
10         recv_size = len(recv_msg)
11 
12     print("命令的结果是:\n\t",recv_msg.decode("gbk"))

 

2、以4个字节为最大发送字节,发送数据

server端(核心代码):

1  length = len(cmd_res)
2 
3             data_length = struct.pack(i,length)
4             conn.send(data_length)
5             conn.send(cmd_res)

client端(核心代码):

1  length_data = tcp_client.recv(4)
2     length = struct.unpack("i",length_data)[0]
3 
4     recv_msg = ‘‘.join(iter(partial(tcp_client.recv,1024),b""))
5 
6     print("命令的结果是:\n\t", recv_msg.decode("gbk"))

需要导入两个包

1 import struct
2 from functools import partial

 

以上是关于socket编程的主要内容,如果未能解决你的问题,请参考以下文章

C++ socket编程 和 MFC socket编程 有啥区别??

socket编程为啥要用wsastartup

Socket编程

Socket编程通过Socket实现TCP编程

Socket网络编程

iOS网络编程笔记——Socket编程