最近在做论文实验,涉及到有关于socket通信的内容,在此做一个总结。
关于Socket的基本内容,我是看了这篇博客,来自于点击打开链接,里面涉及到了有关Python 中socket通信的基本知识。下面介绍一下基于TCP的socket通信基本代码
Server
#server
import socket
import pickle #python 的序列化模块
local=('127.0.0.1', 5000) #绑定的地址和端口号
server=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(local)
server.listen(1)
conn,addr=server.accept()
data=pickle.loads(conn.recv(1024))
conn.close()
Client
#Client
import socket
import pickle
addr=('127.0.0.1',5000)
client=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(addr)
data="hello world"
client.sendall(pickle.dumps(data)) #python3 总sendall()只能发送字节数据,需要通过pickle模块序列化数据
client.close()
上面可以实现简单的socket模块的通信,利用pickle模块我们可以实现发送list,tuple等数据,只需要pickle.dumps(list)后发送数据。
下面说一下子啊具体实验过程中遇到的一些问题,以及自己网上搜到的一些解决方法。
主要的问题是
client.sendall(pickle.dumps(data))
<pre name="code" class="python">data=pickle.loads(conn.recv(1024))
在运行时server端会报如下错误:
ran out of input
主要原因是发送的data数据量太大导致了server端无法完全接受,
conn.recv(1024)
接受的最大字节数为1024,如果数据量不是太大,可以改为
conn.recv(1024*10)
即可解决报错的问题。不过我试了一下太大的数据这样做不行,我有次改为
conn.recv(1024*10000)
发送还是会报错,证明这不是一个好方法。
然后想到的方法是将大量数据线保存成文件,在发送文件到Server端,解析出数据,代码如下
#server
import socket
import pickle #python 的序列化模块
local=('127.0.0.1', 5000) #绑定的地址和端口号
server=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(local)
server.listen(1)
conn,addr=server.accept()
f=open('data','wb') #以wb模式打开data文件,wb代表以字节形式写入文件
while True:
<span style="white-space:pre"> </span>message=conn.recv(1024)
<span style="white-space:pre"> </span>if not message:
<span style="white-space:pre"> </span>break
<span style="white-space:pre"> </span>f.write(message)
f.close()
f=open('data','rb')
data=pickle.load(f) #pickle 的load()函数从一个具有read()或readline()方法的对象中恢复数据
f.close()
conn.close()
#Client
import socket
import pickle
addr=('127.0.0.1',5000)
client=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(addr)
f=open('message','wb')
pickle.dump(message,f)
f.close()
f=open('message','rb')
while 1:
data=f.read(1024)
if not data:
break
s.send(data)
f.close()
client.close()
client.close()
后来在网上搜索发现了另一种简单的方法,如果事先知道要传输的数据的大小,可以将其长度加在发送的数据前面,发送过去,具体如下:
#server
import socket
import struct
import pickle
Host='127.0.0.1'
port=5007
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((Host,port))
s.listen(1)
coon,addr=s.accept()
buff=b''
buff=coon.recv(2) #这里2 是Client端中length的长度大小
length=struct.unpack('!H',buff)[0]
data=pickle.loads(coon.recv(length))
print(data)
coon.close()
#client
import socket
import struct
import pickle
Host='127.0.0.1'
port=5007
data="hello world"
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((Host,port))
packet=pickle.dumps(data)
length=struct.pack('!H',len(packet))
s.sendall(length)
s.sendall(packet)
s.close()
最后发现了另一种最简便的方法:利用multiprocessing.connection 模块的Client和Listener,可以不将数据序列化传输,并且不用指定数据的大小,具体代码如下:
#server
from multiprocessing.connection import Listener
Host='127.0.0.1'
port=5007
server=Listener((Host,port))
conn=server.accept()
data=conn.recv()
conn.close()
#client
from multiprocessing.connection import Client
Host='127.0.0.1'
port=5007
data="hello world"
client=Client((Host,port))
client.send(data)
client.close()