socket编程

  socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议

  Ip层的ip地址可以唯一标识主机,而TCP层协议和端口可以唯一标识主机的一个进程,这样可以利用IP地址+协议+端口号唯一标识网络中的一个进程

  socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用以实现进程在网络中通信。socket是一种“打开-读写-关闭”模式的实现,服务器和客户端各自维护一个“文件”,在建立连接打开后,可以向自己文件写入内容供对方读取或者读取对方内容,通讯结束时关闭文件。

套接字工作流程

  

  服务端先初始化socket,然后与端口绑定(bind),对端口进行接听(listen),调用accept阻塞,等待客户端连接。这时如果有个客户端初始化一个socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器的连接就建立了。客户端发送数据请求,服务器接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

from socket import *

s=socket(AF_INET,SOCK_STREAM) #创建套接字
s.bind(('127.0.0.1',8080)) #绑定IP地址和端口(0-65535)
s.listen(5)
conn,client_addr=s.accept() #链接成功后返回一个链接对象:(链接对象,客户端IP和端口)
#print(conn,client_addr) data=conn.recv(1024) #每次最大收取1024bytes
conn.send(data.upper()) conn.close() #关闭客户端套接字 s.close() #关闭服务器端套接字
服务端套接字函数
s.bind() 绑定(主机,端口号)到套接字
s.listen() 开始TCP监听
s.accept() 被动接受TCP客户的连接,(阻塞式)等待连接的到来 客户端套接字函数
s.connect() 主动初始化TCP服务器连接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
公共用途的套接字函数
s.recv() 接收TCP数据
s.send() 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
s.sendall() 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
s.recvfrom() 接收UDP数据
s.sendto() 发送UDP数据
s.getpeername() 连接到当前套接字的远端的地址
s.getsockname() 当前套接字的地址
s.getsockopt() 返回指定套接字的参数
s.setsockopt() 设置指定套接字的参数
s.close() 关闭套接字

面向锁的套接字方法
s.setblocking() 设置套接字的阻塞与非阻塞模式
s.settimeout() 设置阻塞套接字操作的超时时间
s.gettimeout() 得到阻塞套接字操作的超时时间 面向文件的套接字的函数
s.fileno() 套接字的文件描述符
s.makefile() 创建一个与该套接字相关的文件

基于TCP的套接字

#TCP服务端
from socket import *
s=socket(AF_INET,SOCK_STREAM)
s.bind(('127.0.0.1',8080))
s.listen(5)
while True: #建立和多个客户端链接
print('starting...')
conn,client_addr=s.accept() #阻塞情况1
print(client_addr)
while True:
try:
data=conn.recv(1024) #阻塞情况2
if not data:break #针对linux断开链接后会一直收空消息的处理
print('客户端消息',data)
conn.send(data.upper())
except ConnectionResetError: #非正常断开链接处理
break
conn.close()
#TCP客户端
from socket import *
c=socket(AF_INET,SOCK_STREAM)
c.connect(('127.0.0.1',8080))
while True:
msg=input("message:").strip()
if not msg:continue #客户端发送空消息处理
c.send(msg.encode('utf-8'))
data=c.recv(1024)
print(data)
c.close()
#模拟ssh通信
from socket import *
import subprocess
import struct server=socket(AF_INET,SOCK_STREAM)
server.bind(('127.0.0.1',8081))
server.listen(5) print('starting...')
conn,client_addr=server.accept()
print(client_addr) while True:
try:
cmd=conn.recv(8096)
if not cmd:break obj=subprocess.Popen(cmd.decode('utf-8'),shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
stdout=obj.stdout.read()
stderr=obj.stderr.read() #制作固定长度的报头
total_size=len(stdout)+len(stderr)
headers=struct.pack('i',total_size)
# 发送命令的长度
conn.send(headers) #发送命令的执行结果
conn.send(stdout)
conn.send(stderr)
except ConnectionResetError:
break conn.close()
server.close()

模拟ssh通信_服务端

#模拟ssh通信
from socket import *
import struct client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8081)) while True:
cmd=input("message:").strip()
if not cmd:continue
client.send(cmd.encode('utf-8')) #接收命令长度
headers=client.recv(4)
total_size=struct.unpack('i',headers)[0]
#接收命令结果
recv_size=0
data=b''
while recv_size < total_size:
recv_data=client.recv(1024)
data+=recv_data
recv_size+=len(recv_data) print(data.decode('gbk')) client.close()

模拟ssh通信_客户端

粘包现象及解决方案

  只有TCP有粘包现象,UDP没有。粘包问题主要是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据造成的。

#服务端
from socket import *
import time server=socket(AF_INET,SOCK_STREAM)
server.bind(('127.0.0.1',8081))
server.listen(5) print('starting...')
conn,client_addr=server.accept() res1=conn.recv(1)
print('res1:',res1) time.sleep(6)
res2=conn.recv(10)
print('res2',res2) conn.close()
server.close()
#客户端
from socket import *
import time client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8081)) client.send('hello'.encode('utf-8'))
time.sleep(5)
client.send('world'.encode('utf-8')) client.close()

  解决粘包现象

from socket import *
import subprocess
import struct
import json server=socket(AF_INET,SOCK_STREAM)
server.bind(('127.0.0.1',8081))
server.listen(5) print('starting...')
conn,client_addr=server.accept()
print(client_addr) while True:
try:
cmd=conn.recv(8096)
if not cmd:break obj=subprocess.Popen(cmd.decode('utf-8'),shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
stdout=obj.stdout.read()
stderr=obj.stderr.read() #制作固定长度的报头
headers = {
'filepath': 'a.txt',
'md5': 'fdgre343fg',
'total_size': len(stderr)+len(stdout)
} headers_json = json.dumps(headers)
headers_bytes = headers_json.encode('utf-8') #发送报头的长度
conn.send(struct.pack('i',len(headers_bytes))) # 发送报头
conn.send(headers_bytes) #发送命令的执行结果
conn.send(stdout)
conn.send(stderr)
except ConnectionResetError:
break conn.close()
server.close()

服务端

from socket import *
import struct
import json client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8081)) while True:
cmd=input("message:").strip()
if not cmd:continue
client.send(cmd.encode('utf-8')) #接收报头长度
headers_size=struct.unpack('i',client.recv(4))[0]
#接收报头
headers_bytes=client.recv(headers_size)
headers_json=headers_bytes.decode('utf-8')
headers_dic=json.loads(headers_json)
total_size=headers_dic['total_size'] #接收命令结果
recv_size=0
data=b''
while recv_size < total_size:
recv_data=client.recv(1024)
data+=recv_data
recv_size+=len(recv_data) print(data.decode('gbk')) client.close()

客户端

最新文章

  1. word-wrap ,word-break 和white-space 的联系
  2. 关于Leetcode上二叉树的算法总结
  3. linux 下 ntfs移动硬盘挂载
  4. js实现基础运动
  5. 混乱的url编码||URL编码解码问题
  6. Git CMD - status: Show the working tree status
  7. uva 1346 - Songs(贪心)
  8. Xcode8插件安装
  9. 从零学习Fluter(五):Flutter中手势滑动拖动已经网络请求
  10. BERT(Bidirectional Encoder Representations from Transformers)
  11. Node.js文件编码格式的转换
  12. win10 Faster-RCNN训练自己数据集遇到的问题集锦 (转)
  13. Docker 启动不了容器的问题
  14. Runtime 自动化归档
  15. python学习之思维导图
  16. maven的小知识
  17. css3 transform属性多值的顺序问题
  18. Android动画-帧动画
  19. Delphi 中调用JS文件中的方法
  20. MFC学习(三):项目学习

热门文章

  1. python网络编程part1
  2. kernel对NTP的API,系统调用函数
  3. Project Euler 13 Large sum
  4. 做支付遇到的HttpClient大坑
  5. [置顶] 大数据架构hadoop
  6. ExtJs之Ext.XTemplate:模板成员函数
  7. 带有public static void main方法的类,其中的成员变量必须是static的,否则main方法没法调用。除非是main里的局部变量。因为main方法就是static的啊。
  8. Yarn架构基本概况(二)
  9. Linux--对文件夹下的配置文件批量改动IP
  10. Auto property synthesis will not synthesize property &amp;#39;delegate&amp;#39;; it will be implemented by its super