python3的socket_python3 socket

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

server端:

864672-20170916175720891-1660829390.png

client端 :

864672-20170916175810063-1256264886.png

在此基础上我们建立一个最基本的服务端,客户端(也就是所谓的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()

864672-20170916224228094-584209244.png

大致流程是这样的

864672-20170917095746016-41334037.png

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值