网络编程-套接字(socket)

一、Socket(套接字)

★注意点:

① 127.0.0.1本机地址回环:只能识别自己,其他人无法访问

② send与recv对应,不要出现两边是相同的情况,recv是跟内存要数据,无需考虑

③ tcp特点是会将数据量比较小的并且时间间隔比较短的数据,一次性打包发送给对方

 1 import socket
 2 
 3 server = socket.socket()  # 买手机 不传参数默认用的就是TCP协议
 4 server.bind(('127.0.0.1',8080))  # bind((host,port))  插电话卡  绑定ip和端口
 5 server.listen(5)  # 开机    半连接池
 6 
 7 conn, addr = server.accept()  # 接听电话  等着别人给你打电话    
 8 data = conn.recv(1024)  # 听别人说话 接收1024个字节数据          
 9 conn.send(b'hello baby~')  # 给别人回话
10 
11 conn.close()  # 挂电话
12 server.close()  # 关机
Server端代码
 1 import socket
 2 
 3 client = socket.socket()  # 拿电话
 4 client.connect(('127.0.0.1',8080))  # 拨号   写的是对方的ip和port
 5 
 6 client.send(b'hello world!')  # 对别人说话
 7 data = client.recv(1024)  # 听别人说话
 8 print(data)
 9 
10 client.close()  # 挂电话
Client端代码

二、TCP粘包问题

  我们基于TCP协议写一个远程命令操控

 1 from socket import *
 2 import subprocess
 3 
 4 1024
 5 
 6 tcp_socket_server=socket(AF_INET,SOCK_STREAM)
 7 tcp_socket_server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
 8 tcp_socket_server.bind(('127.0.0.1',8888))
 9 tcp_socket_server.listen(5)
10 
11 while True:
12     conn,addr=tcp_socket_server.accept()
13 
14     while True:
15         cmd=conn.recv(1024)
16         if len(cmd) == 0:break
17 
18         res=subprocess.Popen(cmd.decode('utf-8'),shell=True,
19                          stdout=subprocess.PIPE,
20                          stdin=subprocess.PIPE,
21                          stderr=subprocess.PIPE)
22 
23         stderr=res.stderr.read()
24         stdout=res.stdout.read()
25         conn.send(stderr)
26         conn.send(stdout)
Server
 1 import socket
 2 
 3 s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
 4 res=s.connect_ex(('127.0.0.1',8888))
 5 
 6 while True:
 7     msg=input('>>: ').strip()
 8     if len(msg) == 0:continue
 9     if msg == 'quit':break
10 
11     s.send(msg.encode('utf-8'))
12     act_res=s.recv(1024)
13 
14     print(act_res.decode('utf-8'),end='')
Client

  同时执行多条命令之后,得到的结果可能只有一部分,在执行其他命令的时候又接收到之前执行的另外一部分结果,这种现象就是粘包。

三、解决粘包问题

       问题的根源在于,接收端不知道发送端将要传送的字节流的长度,所以解决粘包的方法就是围绕,如何让发送端在发送数据前,把自己将要发送的字节流总大小让接收端知晓,然后接收端来一个while循环接收完所有数据。

 1 import json
 2 import socket
 3 import struct
 4 import subprocess
 5 
 6 server = socket.socket()
 7 server.bind(('127.0.0.1',8080))
 8 server.listen(5)
 9 
10 while True:
11     conn,addr = server.accept()
12     while True:
13         try:
14             msg = conn.recv(1024).decode('utf-8')
15             if not msg : break
16             obj = subprocess.Popen(msg,shell = True,stdout = subprocess.PIPE,stderr = subprocess.PIPE)
17             res = obj.stdout.read() + obj.stderr.read()
18             dict = {'name':'Spenser','file_size':len(res),'info':'to be a better man'}
19             json_dict = json.dumps(dict)
20             #1.制作字典报头
21             header = struct.pack('i',len(json_dict))
22             #2.传送字典报头
23             conn.send(header)
24             #3.传送字典
25             conn.send(json_dict.encode('utf-8'))
26             #4.传送真实数据
27             conn.send(res)
28         except ConnectionResetError:
29             break
30     conn.close()
server
 1 import socket
 2 import struct
 3 import json
 4 
 5 client = socket.socket()
 6 client.connect(('127.0.0.1',8080))
 7 
 8 while True:
 9     msg = input('>>>:').encode('utf-8')
10     if len(msg) == 0:continue
11     client.send(msg)
12     # 1.先接受字典报头
13     header_dict = client.recv(4)
14     # 2.解析报头 获取字典的长度
15     dict_size = struct.unpack('i',header_dict)[0]  # 解包的时候一定要加上索引0
16     # 3.接收字典数据
17     dict_bytes = client.recv(dict_size)
18     dict_json = json.loads(dict_bytes.decode('utf-8'))
19     # 4.从字典中获取信息
20     print(dict_json)
21     recv_size = 0
22     real_data = b''
23     while recv_size < dict_json.get('file_size'):  # real_size = 102400
24         data = client.recv(1024)
25         real_data += data
26         recv_size += len(data)
27     print(real_data.decode('gbk'))
client

 

posted @ 2019-08-07 20:48  朱朱朱朱朱  阅读(146)  评论(0编辑  收藏  举报