网络编程socket

服务器初始化Socket,端口绑定bind,对端口进行监听listen,调用accept阻塞,等待客户端连接.(之后接收/发送数据),关闭服务器套接字close

客户端初始化socket,连接服务器connect,客户端发送数据请求send,客户端读取回应recv,关闭socket(closet)

TCP

import socket
ip_port=("127.0.0.1",9000)
ss=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ss.bind(ip_port)
ss.listen(5)
while True:
conn=ss.accept()
while True:
conn.recv(1024)
cs.close()
ss.close()

cs=socket.socket()
cs.connect()
while True:
cs.send()#cs.recv()
cs.close()

UDP

ss = socket()   #创建一个服务器的套接字
ss.bind()       #绑定服务器套接字
inf_loop:       #服务器无限循环
     cs = ss.recvfrom()/ss.sendto() # 对话(接收与发送)
ss.close()                         # 关闭服务器套接字
****************************
cs = socket()   # 创建客户套接字
comm_loop:      # 通讯循环
    cs.sendto()/cs.recvfrom()   # 对话(发送/接收)
cs.close()                      # 关闭客户套接字

1.udp的sendinto不用管是否有一个正在运行的服务端,可以己端一个劲的发消息

2.udp的recvfrom是阻塞的,一个recvfrom(x)必须对一个一个sendinto(y),收完了x个字节的数据就算完成,若是y>x数据就丢失,这意味着udp根本不会粘包,但是会丢数据,不可靠

3.tcp的协议数据不会丢,己端总是在收到ack时才会清除缓冲区内容。数据是可靠的,但是会粘包

解决粘包问题(自定义报头)

import json,struct
#假设通过客户端上传1T:1073741824000的文件a.txt

#为避免粘包,必须自定制报头
header={'file_size':1073741824000,'file_name':'/a/b/c/d/e/a.txt','md5':'8f6fbf8347faa4924a76856701edb0f3'} #1T数据,文件路径和md5值

#为了该报头能传送,需要序列化并且转为bytes
head_bytes=bytes(json.dumps(header),encoding='utf-8') #序列化并转成bytes,用于传输

#为了让客户端知道报头的长度,用struck将报头长度这个数字转成固定长度:4个字节
head_len_bytes=struct.pack('i',len(head_bytes)) #这4个字节里只包含了一个数字,该数字是报头的长度

#客户端开始发送
conn.send(head_len_bytes) #先发报头的长度,4个bytes
conn.send(head_bytes) #再发报头的字节格式
conn.sendall(文件内容) #然后发真实内容的字节格式

#服务端开始接收
head_len_bytes=s.recv(4) #先收报头4个bytes,得到报头长度的字节格式
x=struct.unpack('i',head_len_bytes)[0] #提取报头的长度

head_bytes=s.recv(x) #按照报头长度x,收取报头的bytes格式
header=json.loads(json.dumps(header)) #提取报头

#最后根据报头的内容提取真实的数据,比如
real_data_len=s.recv(header['file_size'])
s.recv(real_data_len)
原文地址:https://www.cnblogs.com/arthas-zht/p/6515444.html