网络编程(day2)

网络编程中的服务,客户端与服务端交互命令的时候,有一种现像是粘包,(接收1024个数据)而发送的太多,一次收不完,会收几次,造成信息不正确

粘包:根本原因是TCP协议是一种面向流的协议,

  在客户端粘包,服务端一次发送过多的信息(如cat /etc/passwd),你客户端只接受1024个字符

  在服务端粘包,连续两次发送比较短的数据,因为cpu的速度过快,所以,在缓存中直接连在一起,(因为比网络IO快)

就造成了粘包现像

http://www.cnblogs.com/linhaifeng/articles/6129246.html

subprocess模块    struct模块 参考

struct.pack包,
报头
  一定要固定长度
  包含对将要发送数据的描述信息


socket套接字只能发送bytes格式
编码只能对字符不能编数字所以就有了,struct模块是把数字转成固定长度的bytes

json struct模块解决粘包现像

步骤:

1,定义报头字典

2,json序列化然后,编码成二进制,计算字典的长度(数据的长度在字典中)

3,sturct发送固定长度,把数据字典的长度的发送,再发送数据

4,客户端sturct先收固定的i ,4个字节 ,,得到字典的长度,连续收完字典长度

5,反序列化,解码,然后得到字典,再得到字典中数据长度,开始收数据,

 

########################################

粘包现像代码实例

服务端

#买手机
import socket,time
import subprocess
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#绑定电话卡
ip_port=('127.0.0.1',8080)
phone.bind(ip_port)
phone.listen(5)
conn,addr=phone.accept()


# data1=conn.recv(1024)
# data2=conn.recv(1024)

data1=conn.recv(1) #b'h'

time.sleep(5)
data2=conn.recv(1024) #b'elloworldSB'

#
print('第一个包',data1)
print('第二个包',data2)









客户端

#买手机
import socket,time
import subprocess
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#绑定电话卡
ip_port=('127.0.0.1',8080)
phone.connect(ip_port)

#
phone.send('helloworld'.encode('utf-8'))
time.sleep(3)
phone.send('SB'.encode('utf-8'))

######################################################

 #####################################################

json,struct,  解决粘包问题的服务端与客户端代码(执行显示比较大的命令)

服务端

#coding:utf-8
#买手机
import socket
import struct
import json
import subprocess
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#绑定电话卡
ip_port=('192.168.16.114',8081)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(ip_port)
#开机
phone.listen(5)
#等待电话

#链接循环
while True:
    conn,addr=phone.accept()
    print('client addr',addr)
    #通讯循环
    while True:
        try:
            cmd=conn.recv(1024)
            res=subprocess.Popen(cmd.decode('utf-8'),
                             shell=True,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
            out_res=res.stdout.read()
            err_res=res.stderr.read()
            data_size=len(out_res)+len(err_res)
            head_dic={'data_size':data_size}
            head_json=json.dumps(head_dic)
            head_bytes=head_json.encode('utf-8')

            #part1:先发报头的长度
            head_len=len(head_bytes)
            conn.send(struct.pack('i',head_len))
            #part2:再发送报头
            conn.send(head_bytes)
            #part3:最后发送数据部分
            conn.send(out_res)
            conn.send(err_res)

        except Exception:
            break

    conn.close()
phone.close()

客户端

# 买手机
import socket
import struct
import json
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 拨通电话
# ip_port = ('127.0.0.1', 8080)
ip_port = ('192.168.16.114', 8081)
phone.connect(ip_port)
# 通信循环
while True:
    # 发消息
    cmd = input('>>: ').strip()
    if not cmd: continue
    phone.send(bytes(cmd, encoding='utf-8'))

    # part1:先收报头的长度
    head_struct=phone.recv(4)
    head_len=struct.unpack('i',head_struct)[0]

    # part2:再收报头
    head_bytes=phone.recv(head_len)
    head_json=head_bytes.decode('utf-8')

    head_dic=json.loads(head_json)
    print(head_dic)
    data_size = head_dic['data_size']

    #part3:收数据
    recv_size = 0
    recv_data = b''
    while recv_size < data_size:
        data = phone.recv(1024)
        recv_size += len(data)
        recv_data += data

    print(recv_data.decode('utf-8'))
phone.close()

#######################################################

#######################################################

ftp上传下载文件代码实例 

服务端

import socket
import struct
import json
import subprocess
import os

class MYTCPServer:
    address_family = socket.AF_INET

    socket_type = socket.SOCK_STREAM

    allow_reuse_address = False

    max_packet_size = 8192

    coding='utf-8'

    request_queue_size = 5

    server_dir='file_upload'

    def __init__(self, server_address, bind_and_activate=True):
        """Constructor.  May be extended, do not override."""
        self.server_address=server_address
        self.socket = socket.socket(self.address_family,
                                    self.socket_type)
        if bind_and_activate:
            try:
                self.server_bind()
                self.server_activate()
            except:
                self.server_close()
                raise

    def server_bind(self):
        """Called by constructor to bind the socket.
        """
        if self.allow_reuse_address:
            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.socket.bind(self.server_address)
        self.server_address = self.socket.getsockname()

    def server_activate(self):
        """Called by constructor to activate the server.
        """
        self.socket.listen(self.request_queue_size)

    def server_close(self):
        """Called to clean-up the server.
        """
        self.socket.close()

    def get_request(self):
        """Get the request and client address from the socket.
        """
        return self.socket.accept()

    def close_request(self, request):
        """Called to clean up an individual request."""
        request.close()

    def run(self):
        while True:
            self.conn,self.client_addr=self.get_request()
            print('from client ',self.client_addr)
            while True:
                try:
                    head_struct = self.conn.recv(4)
                    if not head_struct:break

                    head_len = struct.unpack('i', head_struct)[0]
                    head_json = self.conn.recv(head_len).decode(self.coding)
                    head_dic = json.loads(head_json)

                    print(head_dic)
                    #head_dic={'cmd':'put','filename':'a.txt','filesize':123123}
                    cmd=head_dic['cmd']
                    if hasattr(self,cmd):
                        func=getattr(self,cmd)
                        func(head_dic)
                except Exception:
                    break

    def put(self,args):
        file_path=os.path.normpath(os.path.join(
            self.server_dir,
            args['filename']
        ))

        filesize=args['filesize']
        recv_size=0
        print('----->',file_path)
        with open(file_path,'wb') as f:
            while recv_size < filesize:
                recv_data=self.conn.recv(self.max_packet_size)
                f.write(recv_data)
                recv_size+=len(recv_data)
                print('recvsize:%s filesize:%s' %(recv_size,filesize))


tcpserver1=MYTCPServer(('127.0.0.1',8080))

tcpserver1.run()







客户端

import socket
import struct
import json
import os



class MYTCPClient:
    address_family = socket.AF_INET

    socket_type = socket.SOCK_STREAM

    allow_reuse_address = False

    max_packet_size = 8192

    coding='utf-8'

    request_queue_size = 5

    def __init__(self, server_address, connect=True):
        self.server_address=server_address
        self.socket = socket.socket(self.address_family,
                                    self.socket_type)
        if connect:
            try:
                self.client_connect()
            except:
                self.client_close()
                raise

    def client_connect(self):
        self.socket.connect(self.server_address)

    def client_close(self):
        self.socket.close()

    def run(self):
        while True:
            inp=input(">>: ").strip()
            if not inp:continue
            l=inp.split()
            cmd=l[0]
            if hasattr(self,cmd):
                func=getattr(self,cmd)
                func(l)


    def put(self,args):
        cmd=args[0]
        filename=args[1]
        if not os.path.isfile(filename):
            print('file:%s is not exists' %filename)
            return
        else:
            filesize=os.path.getsize(filename)

        head_dic={'cmd':cmd,'filename':os.path.basename(filename),'filesize':filesize}
        print(head_dic)
        head_json=json.dumps(head_dic)
        head_json_bytes=bytes(head_json,encoding=self.coding)

        head_struct=struct.pack('i',len(head_json_bytes))
        self.socket.send(head_struct)
        self.socket.send(head_json_bytes)
        send_size=0
        with open(filename,'rb') as f:
            for line in f:
                self.socket.send(line)
                send_size+=len(line)
                print(send_size)
            else:
                print('upload successful')




client=MYTCPClient(('192.168.16.114',8080))

client.run()
原文地址:https://www.cnblogs.com/wanchenxi/p/7734954.html