安迪_963

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

python 套接字编程的大致流程如下:

server端:

client端 :

 

在此基础上我们建立一个最基本的服务端,客户端(也就是所谓的cs模型)

server:

#!/usr/bin/env python
#coding:utf-8
#Created by Andy @ 2017/9/16


import socket

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("127.0.0.1", 8081))
server.listen(5)

conn, client_addr = server.accept()
msg = conn.recv(1024)

print(msg)
conn.close()
server.close()

 client

#!/usr/bin/env python
#coding:utf-8
#Created by Andy @ 2017/9/16


import socket

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(("127.0.0.1", 8081))

client.send("hello, server".encode("utf-8"))
client.close()

 这大概是最简单的cs模型了,事实上这样只完成了一次从客户端向服务端发送了一条消息,然后就关闭了连接。在实际情况中,服务端应该始终保持链接,通信也就是

上图中的链接循环,通信循环。

我们对上面的代码进行修改:

server:

#!/usr/bin/env python
#coding:utf-8
#Created by Andy @ 2017/9/16


import socket

BUFF_SIZE = 1024
IP_PORT = ("127.0.0.1", 8081)

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(IP_PORT)
server.listen(5)

while True:
    conn, client_addr = server.accept()

    while True:
        msg = conn.recv(BUFF_SIZE)
        if not msg:
            break
        else:
            conn.send(msg)
            msg = msg.decode("utf-8")
            print(client_addr, msg)

    conn.close()
server.close()

 client:

#!/usr/bin/env python
#coding:utf-8
#Created by Andy @ 2017/9/16


import socket

BUFF_SIZE = 1024
IP_PORT = ("127.0.0.1", 8081)

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(IP_PORT)

while True:
    msg = input(">>:").strip().encode("utf-8")
    if not msg:
        break
    else:
        client.send(msg)

    response = client.recv(BUFF_SIZE)
    if response:
        print(response.decode("utf-8"))

client.close()

 这样就实现了简单的链接循环,通信循环。

但还有一个问题,就是可能出现粘包,

 

1.由于tcp的机制,假如我一次只发送了5bytes的数据,它可能只是缓存起来了,并没有直接发送,

等到我再次发送了若干数据(如100bytes)后它将这些数据一起发送出去,这样数据在客户端已经粘包。

2.同样,在服务端解码时也可能出现,也可能出现粘包现象,即将前后多个包一次解码,数据在服务端出现粘包。

 

那么,要怎么解决呢?

可以看到问题就出在解包时不知道某个包的具体长度是多少,如果我们知道某个包的长度,只需要按照这个包的长度

去解包,即使它粘包了,我们仍然能解出正确的数据来。

  

那么就需要我们来定制报头,来告知解码的一方这个包的长度:

下面以模拟ssh来做这个例子,

我们约定报头的长度为四个字节。

server:

#!/usr/bin/env python
#coding:utf-8
#Created by Andy @ 2017/9/16


import socket,json, struct, subprocess

BUFF_SIZE = 1024
IP_PORT = ("127.0.0.1", 8081)

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)# 重用端口
server.bind(IP_PORT)
server.listen(5)# 设置可以接受的连接数量

while True:# 外层循环为链接循环
    conn, client_addr = server.accept()

    while True:# 内层循环为通信循环
        msg = conn.recv(BUFF_SIZE)
        if not msg:
            break
        pipes = subprocess.Popen(msg.decode("utf-8"),
                                 shell=True,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE
                                 )

        error = pipes.stderr.read()
        if error:
            print("Error:",error)
            response_msg = error
        else:
            response_msg = pipes.stdout.read()

        header = {'data_size':len(response_msg)}# 数据长度
        header_json = json.dumps(header)#序列化
        header_json_byte = bytes(header_json,encoding="utf-8")

        conn.send(struct.pack('i',len(header_json_byte)))
        #先发送报头长度,仅包含数据长度, 这里的i指int类型
        conn.send(header_json_byte)# 再发送报头
        conn.sendall(response_msg)# 正式的信息
        print("Request from:",client_addr, "Command:",msg)

    conn.close()
server.close()

 client:

#!/usr/bin/env python
#coding:utf-8
#Created by Andy @ 2017/9/16


import socket, json, struct

BUFF_SIZE = 1024
IP_PORT = ("127.0.0.1", 8081)

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(IP_PORT)

while True:
    msg = input(">>:").strip().encode("utf-8")
    if not msg:
        break

    client.send(msg)

    header = client.recv(4)
    print("Header:",struct.unpack("i", header))
    header_length = struct.unpack('i', header)[0]
    print("Header_length:", header_length)
    header_json = json.loads(client.recv(header_length).decode("utf-8"))
    data_size = header_json['data_size']
    print("Data_size:",data_size)

    recv_size = 0
    recv_data = b''

    while recv_size < data_size:
        recv_data += client.recv(BUFF_SIZE)
        recv_size += len(recv_data)

    print(recv_data.decode("gbk"))

client.close()

 

 大致流程是这样的

事实上,上面的例子只完成了一个客户端与服务器进行通信的功能,并没有实现如

server端中写的server.listen(5),同时与5个客户端通信,要看如何实现可以参考:

python3 进程

 

posted on 2017-09-16 22:44  Andy_963  阅读(342)  评论(0编辑  收藏  举报