python 通信相关包_Python_编写UDP通信编解码类、文件的上传、远程执行命令、黏包...

1、UDP通信编解码类

(1) 类

1 #------------------UDP通信解码编码类------------------------

2

3 from socket import *

4

5 classMy_Socket(socket):6 def __init__(self,coding='utf-8'):7 self.coding =coding8 super(My_Socket, self).__init__(type=SOCK_DGRAM)9

10 defmy_recv(self,num):11 msg,addr =self.recvfrom(num)12 returnmsg.decode(self.coding),addr13

14 defmy_send(self,msg,addr):15 return self.sendto(msg.encode(self.coding),addr)

(2) UDP通信客户端(调用自己的解码编码类)

#--------------UDP通信客户端(调用自己的解码编码类)-----------------

from MySocket importMy_Socket

sk=My_Socket()

msg_s= input('>>>')

sk.my_send(msg_s,('127.0.0.1',8080))

sk.close()

UDP通信客户端(调用自己的解码编码类)

(3) UDP通信服务器端(调用自己的解码编码类)

1 #-----------UDP通信服务器端(调用自己的解码编码类)---------------

2

3 from MySocket importMy_Socket4

5 sk =My_Socket()6

7 sk.bind(('127.0.0.1',8080))8

9 msg_r,addr = sk.my_recv(1024)10

11 print(msg_r)12

13 sk.close()

UDP通信服务器端(调用自己的解码编码类)

2、文件的上传(服务器端)

(1)只能上传小文件。

1 importsocket2 importjson3 sk =socket.socket()4

5 sk.bind(('127.0.0.1',8080))6

7 sk.listen(5)8

9 conn,addr =sk.accept()10

11 #上传下载的逻辑

12 str_dic = conn.recv(1024).decode('utf-8')13 dic =json.loads(str_dic)14 #dic = {'opt':ls.get(num),'filename':filename,'content':content}

15 if dic['opt'] == 'upload':16 filename = 'new_'+dic['filename']17 with open(filename,'w',encoding='utf-8') as f:18 f.write(dic['content'])19

20 conn.close()21 sk.close()

只能传小文件(服务器端)

(2)通过方法:先获取文件大小,然后把文件大小加入到字典中,把字典发过去接收端就可以知道文件大小了,就可以根据文件大小进行接收大文件了。

问题:可能黏包的问题,就是send了字典之后,就send了文件内容。

解决的方法:在两个send之间加了一个recv,接收一个success 。

1 importsocket2 importjson3 sk =socket.socket()4

5 sk.bind(('127.0.0.1',8080))6

7 sk.listen(5)8

9 conn,addr =sk.accept()10

11 #上传下载的逻辑

12 str_dic = conn.recv(1024).decode('utf-8')#先接受到字符串形式的字典

13 conn.send(b'success')#给客户端回复一个成功,代表字典接收成功了,也是把字典内容和接下来要接收的文件内容分割开

14 dic = json.loads(str_dic)#反序列化,将字典还原出来

15 #dic = {'opt':ls.get(num),'filename':filename,'content':content}

16 if dic['opt'] == 'upload':17 filename = 'new_'+dic['filename']#产生一个新的文件名

18 filesize = dic['filesize']#获取文件的大小

19 with open(filename,'wb') as f:20 whilefilesize:21 content = conn.recv(1024)22 filesize -= len(content)#减去接收到的长度,而不能直接减去1024

23 f.write(content)24

25 conn.close()26 sk.close()

以下解决黏包现象,实现大文件的传输,比较low比的方法

(3)先把字典的大小获取,然后server先接收字典的大小,然后根据字典大小去接收字典,这样就直接解决了2中的问题。

1 importsocket2 importjson3 sk =socket.socket()4

5 sk.bind(('127.0.0.1',8080))6

7 sk.listen(5)8

9 conn,addr =sk.accept()10

11

12 #我算出来了字典长度为70(属于作弊),这个‘70’是两个字节的长度,所以接收两个字节长度,把字典大小接收到

13 len_dic = int(conn.recv(2).decode('utf-8'))#在这里转成int以便下一行代码中当做recv的参数

14 #这个len_dic = 70,转码后是字符串

15

16 str_dic = conn.recv(len_dic).decode('utf-8')#根据字典长度去接收字典,防止接收到文件的内容

17

18 #在这里,上边代码我明确了字典大小,就可以按照字典大小接收固定长度,这样之后,就可以防止上边接收到 下边应该接收的文件内容

19 #此时我就可以省略一个 sk.send(b'success')这句话,就可以少一个网络传输数据时的延时。

20 dic =json.loads(str_dic)21 #dic = {'opt':ls.get(num),'filename':filename,'filesize':filesize}

22 if dic['opt'] == 'upload':23 filename = 'new_'+dic['filename']24 filesize = dic['filesize']25 with open(filename,'wb') as f:26 whilefilesize:27 content = conn.recv(1024)28 filesize -=len(content)29 f.write(content)30

31 conn.close()32 sk.close()

比较中端的方法

(4)字典的大小不固定,所以我使用了struct模块中的pack方法,解决这个事情,使字典的大小这个数字无论多少位,我都固定生成一个4位的bytes,这样server端就可以直接先接收4个字节了,通过unpack获取字典大小。

1 importsocket2 importjson3 importstruct4 sk =socket.socket()5

6 sk.bind(('127.0.0.1',8080))7

8 sk.listen(5)9

10 conn,addr =sk.accept()11

12

13 #上边说了,如果我在这里明确接收2个字节就可以接收到字典的大小,这是作弊

14 #因为字典大小如果是 100~999 ,我这里就要接收3个字节

15 #如果字典大小是 100000 ~ 999900 ,我这里就要接收6个字节

16 #所以为了公正,我使用了struct,在客户端先把‘字典大小’的长度固定为4个字节

17 len_dic = conn.recv(4)#此时接收到了 字典的长度,不过是经过struct.pack处理后的

18 len_str_dic = struct.unpack('i',len_dic)[0] #在这里,得到int型的字典长度,注意:unpack方法返回一个元组。

19

20 str_dic = conn.recv(len_str_dic).decode('utf-8')#根据字典长度去接收字典,防止接收到文件的内容

21

22

23 dic =json.loads(str_dic)24 #dic = {'opt':ls.get(num),'filename':filename,'filesize':filesize}

25 if dic['opt'] == 'upload':26 filename = 'new_'+dic['filename']27 filesize = dic['filesize']28 with open(filename,'wb') as f:29 whilefilesize:30 content = conn.recv(1024)31 filesize -=len(content)32 f.write(content)33

34 conn.close()35 sk.close()

比较高端的方法,使用struct

3、远程执行命令

(1) 远程执行命令(服务器端)

1 #------------------远程执行命令(服务器端)------------------------

2

3 importsocket4 importsubprocess5

6 sk =socket.socket()7 sk.bind(("127.0.0.1", 8080))8 sk.listen(5)9

10 conn, addr =sk.accept()11

12 while 1:13 cmd = conn.recv(1024).decode('utf-8')14 r = subprocess.Popen(cmd, shell=True,15 stdout=subprocess.PIPE,16 stderr=subprocess.PIPE)17 stdout =r.stdout.read()18 stderr =r.stderr.read()19 ifstdout:20 conn.send(stdout)21 elifstderr:22 conn.send(stderr)23

24 conn.close()25 sk.close()

远程执行命令(服务器端)

(2) 远程执行命令(客户端)

1 #---------------远程执行命令(客户端)--------------------

2

3 importsocket4

5 sk =socket.socket()6

7 sk.connect(('127.0.0.1', 8080))8

9 while 1:10 cmd = input('>>>')11 sk.send(cmd.encode('utf-8'))12 ret_1 = sk.recv(1024).decode('gbk')13 ret_2 = sk.recv(1024).decode('gbk')14 print(ret_1)15

16 sk.close()

远程执行命令(客户端)

4、黏包

黏包:是指可能是:接收端和发送端两端在进行收发时,数据大小不统一造成的.

也可能是:合包机制和nagle算法的实现,而没有提供科学的拆包机制,造成的.

一种是因为:client连续发送少量数据,时间间隔短,所以nagle算法帮你合包了,但是此时server不知道要接收多少,所以造成数据混乱

一种是因为:client直接发送了大量数据,但是server端接收的长度不够,所以造成数据混乱

(1) UDP_黏包_服务器

1 importsocket2

3 sk = socket.socket(type=socket.SOCK_DGRAM)4

5 sk.bind(('127.0.0.1', 8080))6

7 msg, addr = sk.recvfrom(1024)8

9 print(msg)10

11 sk.close()

UDP_黏包_客户端

(2) UDP_黏包_客户端

1 importsocket2 sk = socket.socket(type=socket.SOCK_DGRAM)3

4 sk.sendto(b'123',('127.0.0.1',8080))5 sk.sendto(b'abc',('127.0.0.1',8080))6 sk.close()

UDP_黏包_客户端

(3) TCP_nagle_服务器端

TCP_nagle_服务器端

(4) TCP_nagle_客户端

1 importsocket2

3 BUFSIZE = 1024

4 ip_port = ('127.0.0.1', 8080)5

6 s = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)7 res =s.connect_ex(ip_port)8

9 s.send('hello egg'.encode('utf-8'))

TCP_nagle_客户端

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值