之前想要写一个简洁的小型服务器,包括 Server 和 Client,所以用到了 Python 的 socket 模块。
这里先附上 两段代码
- Server
#!/usr/bin/python
# -*- coding: utf-8 -*-
import socket
print 'Start listening...'
HOST='129.173.67.53'
# PORT=52631
# HOST='localhost'
PORT=3306
print("IP Addr : " + HOST , " , PORT : " + str(PORT))
s= socket.socket(socket.AF_INET,socket.SOCK_STREAM)
// 绑定 IP 和 端口
s.bind((HOST,PORT))
s.listen(1)
while 1:
conn,addr=s.accept()
print 'Connected by ', addr
text1 = conn.recv(1024)
print "Text 1 :" + text1
text2 = conn.recv(1024)
# print "Text 1 : " + text1
print "Text 2 : " + text2
result = str(gtmapi.textSimilarity(text1 , text2))
conn.sendall(result)
print "Sim : " + result
conn.close()
jpype.shutdownJVM()
- Client
#!/usr/bin/python
# -*- coding: utf-8 -*-
import socket
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect the socket to the port where the server is listening
server_address = ('localhost', 8001)
#server_address = ('129.173.67.53', 3306)
print 'connecting to'
print server_address
sock.connect(server_address)
while 1:
text1 = "Im sitong"
text2 = "I am no sitong"
sock.sendall(text1)
sock.sendall(text2)
result = sock.recv(1024)
print "Sim : " + result
sock.close()
break
讨论
运行了上面的代码之后,你会发现个是有问题的,问题就是 你 recv 获取的两个text 的内容可能是错误的。例如
// sent texts
text1 = "I am apple."
text2 = "I like apple."
// recv texts
text1 = "I am"
text2 = apple. I like apple.
就是因为 sendall 发送的信息给 client之后, 并不能保证 client 一次性全部都收到。而且使用的 sendall 的次数和 recv 的次数是没有关系的。也就是说, 并不是你连续使用两次sendall, 就可以使用 两个 recv 来分别接收两次发送的数据。
解决的办法有三个:
- 基础的接收方法
因为当与服务器的socket 断开之后,client 会接受到空字符串,所以可以直接加上循环接收数据,当收到空字符串的时候就是结束了。代码如下:
import socket,struct,sys,time
Port=22220
#assume a socket disconnect (data returned is empty string) means all data was #done being sent.
def recv_basic(the_socket):
total_data=[]
while True:
data = the_socket.recv(20480)
if not data: break
total_data.append(data)
return ''.join(total_data)
- 尾部标记法
就是设置好一个约定,当接收到的数据结尾包含某个字符串的时候,就代表数据传输结束了。
代码如下:
End='something useable as an end marker'
def recv_end(the_socket):
total_data=[];data=''
while True:
data=the_socket.recv(8192)
if End in data:
total_data.append(data[:data.find(End)])
break
total_data.append(data)
if len(total_data)>1:
#check if end_of_data was split
last_pair=total_data[-2]+total_data[-1]
if End in last_pair:
total_data[-2]=last_pair[:last_pair.find(End)]
total_data.pop()
break
return ''.join(total_data)
- 负载长度方法
就是在数据传输一开始 写明要传输的数据的长度。这要求接收方一边接收数据,一遍解析数据。
代码如下:
def recv_size(the_socket):
#data length is packed into 4 bytes
total_len=0;total_data=[];size=sys.maxint
size_data=sock_data='';recv_size=8192
while total_len<size:
sock_data=the_socket.recv(recv_size)
if not total_data:
if len(sock_data)>4:
size_data+=sock_data
size=struct.unpack('>i', size_data[:4])[0]
recv_size=size
if recv_size>524288:recv_size=524288
total_data.append(size_data[4:])
else:
size_data+=sock_data
else:
total_data.append(sock_data)
total_len=sum([len(i) for i in total_data ])
return ''.join(total_data)
网友评论