Socket 小知识

2017-04-01  本文已影响0人  四月白绵羊

之前想要写一个简洁的小型服务器,包括 ServerClient,所以用到了 Pythonsocket 模块。
这里先附上 两段代码

  1. 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()

  1. 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 来分别接收两次发送的数据。
解决的办法有三个:

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)
上一篇 下一篇

猜你喜欢

热点阅读