socket基本语法和粘包

Posted mcc61

tags:

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

一。基本语法

127.0.0.1     是本地回环地址

客户端                                                                                                                                                                          服务端

import socket                                                                                                                                                               import socket

client=socket.socket()                                                                                                                                                  server=socket.socket()         #买手机
ip_port=(‘127.0.0.1‘,8088)                                                                                                                                            ip_port=(‘127.0.0.1‘,8088)

client.connect(ip_port)   #连接的是一个元组,所以提前写好需要输入的IP和port                                                        server.bind(ip_port)             #插电话卡  注意括号内是一个小元组,避免出错,先将Ip_port先写在外面

                                                   server.listen(5)                    #监听状态   5是半连接池

                                                  conn,addr=server.accept()   #建立通信,已完成三次握手

client.secd(b‘hello boy!‘)                                                   data=conn.recv (1024)        #   和客户端对照者写,move right   必须是一个输入,一个接受,否则就会出现双方都在输入/输出状态,就会出现阻塞现象

                                                                                                 print(data)

data=client.recv(1024)                                         conn.send(b‘hihihihihi‘)                                       

 

print(data)                                              conn.close()

client.close()    #一次通信结束                                     server.close()

 

二。通信循环

上面我们已经可以实现两个计算机之间的相互通信,但是只是一次通信,如果要多次通信,就得多次输入,我们前面学过的可以多次输入的有什么?while循环

客户端                                                                                                                                                                          服务端

import socket                                                                                                                                                               import socket

client=socket.socket()                                                                                                                                                  server=socket.socket()         #买手机
ip_port=(‘127.0.0.1‘,8088)                                                                                                                                            ip_port=(‘127.0.0.1‘,8088)

client.connect(ip_port)   #连接的是一个元组,所以提前写好需要输入的IP和port                                                        server.bind(ip_port)             #插电话卡  注意括号内是一个小元组,避免出错,先将Ip_port先写在外面

                                                   server.listen(5)                    #监听状态   5是半连接池

                                                  conn,addr=server.accept()   #建立通信,已完成三次握手

while True:                                             while True:

  client.send(b‘hello boy!‘)                                                     data=conn.recv (1024)   

                                                                                                     print(data)

  data=client.recv(1024)                                           conn.send(b‘hihihihihi‘)                                       

  print(data)                                              

                                                   conn.close()

client.close()    #一次通信结束                                     server.close()

 

三。链接循环

通信循环也已经实现了两台计算机之间的多次信息交流,但是发现只能一次服务一个客户端,但是服务端的特点是24小时不间断的提供服务,并且是提供给多个用户,地址也是不变的,那么如何实现提供多个服务给用户呢?链接循环走起来!

客户端                                                                                                                                                                          服务端

import socket                                                                                                                                                               import socket

client=socket.socket()                                                                                                                                                  server=socket.socket()         #买手机
ip_port=(‘127.0.0.1‘,8088)                                                                                                                                            ip_port=(‘127.0.0.1‘,8088)

client.connect(ip_port)   #连接的是一个元组,所以提前写好需要输入的IP和port                                                        server.bind(ip_port)             #插电话卡  注意括号内是一个小元组,避免出错,先将Ip_port先写在外面

                                                   server.listen(5)                    #监听状态   5是半连接池

                                              while True:   #这里就可以实现多个客户服务,所以得将建立连接信息放到第一个while里面     我们发现最多只可以打开6个客户端,一旦超过就报错

                                                   这是因为半连接池是5,就相当于只提供了5个凳子,先服务第一个用户,外面可以由5个人在 等,但是再来一个就报错!

                                                  conn,addr=server.accept()   #建立通信,已完成三次握手

while True:                                             while True:

  client.send(b‘hello boy!‘)                                                     data=conn.recv (1024)   

                                                                                                     print(data)

  data=client.recv(1024)                                           conn.send(b‘hihihihihi‘)                                       

  print(data)                                              

                                                   conn.close()

client.close()    #一次通信结束                                     server.close()

 

四。异常处理

实际生活中:

1,用户提前中断了通道,会发现服务端直接报错,所以要对这个进行异常捕获

2.网络信号不好导致的问题

3.tcp协议是流的传输,输入信息不可以是空

 

客户端                                                                                                                                                                          服务端

import socket                                                                                                                                                               import socket

client=socket.socket()                                                                                                                                                  server=socket.socket()         #买手机
ip_port=(‘127.0.0.1‘,8088)                                                                                                                                            ip_port=(‘127.0.0.1‘,8088)

client.connect(ip_port)   #连接的是一个元组,所以提前写好需要输入的IP和port                                                        server.bind(ip_port)             #插电话卡  注意括号内是一个小元组,避免出错,先将Ip_port先写在外面

                                                   server.listen(5)                    #监听状态   5是半连接池

                                              while True:  

                                                  conn,addr=server.accept()   #建立通信,已完成三次握手

while True: 

  msg=input(‘>>>:‘).encode(‘utf-8‘) 

  if len(msg)==0:continue                                        while True:

                                                     try:

  client.send(msg)                                                          data=conn.recv (1024) 

                                                        if len(data)==0:break   #针对mac 和Linux系统,需要自己再加一步 

                                                                                                       print(data)

  data=client.recv(1024)                                             conn.send(b‘hihihihihi‘)                                       

  print(data)                                               except ConnectionRaseError:break

                                                   conn.close()

client.close()    #一次通信结束                                     server.close()

 

五。粘包问题

发现当自己输入的是task list之类的东西时,然后再次输入dir但是还是接收的是task list的信息,就是粘包,两个数据粘在了一起,解决方式

1.将recv的值改大,但是不是根本性的解决方式,因为你不知道用户传入的东西是多大,所以不推荐

2.将我们要传的东西先打包成固定大小,对方接受以后解包,看到大小,然后再根据大小来接受我们要传的东西(看下面总结)

总结:

发送消息端:

1.先发报头    2.在发字典(序列化成字符串)       3.再发你的真实数据

接收消息端:

1.先收4个长度的报头   2.解包拿到字典数据长度    3.接收字典(反序列化)获取字典里面的所有信息         4.接收真实数据

用到的模块分别是struck(pack,unpack),subprocess(标准输出stdout和错误流stderr)  json(序列化dumps和反序列化loads)   以及socket

客户端

import socket
import json
import struct
client=socket.socket()
ip_port=(‘127.0.0.1‘,8099)
client.connect(ip_port)

while True:
msg=input(‘>>>:‘).strip().encode(‘utf-8‘)
if len(msg)==0:continue
client.send(msg)
head=client.recv(4) #head就是4
#对这个报头进行解包,获取真实数据的长度
head_len=struct.unpack(‘i‘,head)[0]
head_dic=json.loads(client.recv(head_len).decode(‘utf-8‘)) #反序列化
print(head_dic)

total_size=head_dic[‘len‘] #一定要由索引0
# unpack拿出来的是一个小元组
print(total_size)

#如果发送内容过大,怎么做,循环接收值

recv_size=0
res=b‘‘
while recv_size<total_size: #对需要的数据进行循环接受
data=client.recv(1024)
res+=data
recv_size+=len(data) #len(data)真实收到的数据,所以是data,不是1024
print(res.decode(‘gbk‘))

服务端:

#服务端给用户端发送一个字典的内容
import socket
import struct
import json
import subprocess

server=socket.socket()

ip_port=(‘127.0.0.1‘,8099)

server.bind(ip_port)

server.listen(5)

while True:

conn,addr=server.accept()

while True:
try:
data=conn.recv(1024)
if len(data)==0:break
print(data)
order=subprocess.Popen(data.decode(‘utf-8‘),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)

stdout=order.stdout.read()
stderr=order.stderr.read()
#传过来的真实长度
print(len(stderr+stdout))
#传字典
head_dic = {
‘file_name‘: ‘cls.txt‘,
‘len‘: len(stdout + stderr)
}
#字典序列化
head_bytes=json.dumps(head_dic).encode(‘utf-8‘)

#制作报头
head=struct.pack(‘i‘,len(head_bytes)) #将需要发送给客户端的打包成4个字节

conn.send(head) #head=4想拿到一些描述,传个字典

conn.send(head_bytes)
conn.send(stderr+stdout)
except ConnectionResetError:break

 

以上是关于socket基本语法和粘包的主要内容,如果未能解决你的问题,请参考以下文章

python 网络编程 缓冲和粘包

UDP套接字和粘包

解决缓存不够无法接收全部数据和粘包问题

4-10:TCP协议之面向字节流和粘包问题

TCP-缓冲区和粘包、拆包有啥关系?

TCP 的断包和粘包