美文网首页
Socket 小知识

Socket 小知识

作者: 四月白绵羊 | 来源:发表于2017-04-01 00:56 被阅读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 来分别接收两次发送的数据。
    解决的办法有三个:

    • 基础的接收方法
      因为当与服务器的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)
    

    相关文章

      网友评论

          本文标题:Socket 小知识

          本文链接:https://www.haomeiwen.com/subject/udbbottx.html