理解Socket

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

其实在我看来socket就是一个模块.我们通过模块中已经实现的方法建立两个进程之间的连接和通信.

socket层

          

TCP协议和UDP协议

TCP:可靠的,面向连接的协议(eg:打电话),传输效率低全双工通信(发送缓存&接受缓存),面向字节流.使用TCP的应用:Web浏览器;电子邮件,文件传输程序.

UDP:不可靠的,无连接的服务,传输效率高,一对一,一对多,多对一,多对多,面向报文,尽最大努力服务,无拥塞控制.使用UDP的应用:域名系统(DNS):视频流,IP语音.

    

套接字(socket)初使用

基于TCP协议的socket

tcp是基于连接的,必须先启动服务端,然后启动客户端去链接服务端

server端

import socket
sk = socket.socket()
sk.bind(('192.168.13.118',8899))   #绑定地址和端口到套接字
sk.listen()       #监听链接
conn,addr = sk.accept()    #接受客户端链接
ret = conn.recv(1024)     #接受客户端信息
print(ret)     #打印客户端信息
conn.close(b'hello')       #向客户端发送信息
conn.close()         #关闭客户端套接字
sk.close()          #关闭服务器套接字

server端

client端

import socket
sk = socket.socket()            #创建客户套接字
sk.connect(('192.168.13.118',8899))      #尝试链接服务器
sk.send(b'hello')
ret = sk.recv(1024)          #对话(发送/接收)
print(ret)
sk.close()                #关闭客户端套接字

client端

基于UDP协议的socket

udp 是无连接的,启动服务之后就可以直接接收消息,不需要提前建立连接

#server端
import socket
sk = socket.socket(type = socket.SOCK_DGRAM)   #创建一个服务器套接字
sk.bind(('192.168.13.118',8899))    #绑定服务器套接字
conn,addr = sk.recvfrom(1024)
print(conn)
sk.sendto(b'hi',addr)       #对话
sk.close()          #关闭服务器套接字

#client端

ip_port = ('192.168.13.118',8899)
sk = socket.socket(type = socket.SOCK_DGRAM)
sk.sendto(b'hello',ip_port)
conn,addr = sk.recvfrom(1024)
print(conn.decode('utf-8'),addr)

黏包

res = subprocess.Popen(cmd.decode('utf-8'),
shell = True,
stderr = subprocess.PIPE,
stdout = subprocess.PIPE)编码是以当前所在系统为准的,如果Windows,那么res.stdout.read()读出的就是GBK编码,同时需要GBK解码且只能从管道里读取一次结果

黏包现象

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

注意:只有TCP有黏包现象,UDP永远不会黏包

黏包成因:

tcp协议的拆包机制

  当发送端缓冲区的长度大于网卡的MTU时,tcp会将这次发送的数据拆成几个数据包发送出去.

MTU是Maximum Transmission Unit的缩写.意思是网络上传送的最大数据包.MTU的单位是字节.大部分网络设备的MTU都是1500.如果本机的MTU比网关的MTU大,大的数据包就会被拆开来传送,这样会产生很多的数据碎片,增加丢包率,降低网络速度.

面向流的通信特点和Nagle算法

TCP(transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务。
收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。
这样,接收端,就难于分辨出来了,必须提供科学的拆包机制。 即面向流的通信是无消息保护边界的。
对于空消息:tcp是基于数据流的,于是收发的消息不能为空,这就需要在客户端和服务端都添加空消息的处理机制,防止程序卡住,而udp是基于数据报的,即便是你输入的是空内容(直接回车),也可以被发送,udp协议会帮你封装上消息头发送过去。
可靠黏包的tcp协议:tcp的协议数据不会丢,没有收完包,下次接收,会继续上次继续接收,己端总是在收到ack时才会清除缓冲区内容。数据是可靠的,但是会粘包。

会发生黏包的两种情况

情况一,发送方的缓存机制

from socket import *ip_port = ('127.0.0.1',8899)tcp_socket_server = socket(AF_INET,SOCK_STREAM)
tcp_socket_server.bind(in_port)
tcp_socket_server.listen(5)conn,addr = tcp_socket_server.accept()data1 = conn.recv(10)
data2 = conn.recv(10)print('---->',data1.decode('utf8'))
print('---->',data2.decode('utf8'))conn.close()

服务端

import socket
BUFSIZE = 1024
ip_port=('127.0.0.1',8899)sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
res = s.connect_ex(ip_port)sk.send('hello'.encode('utf-8'))
sk.send('egg'.encode('utf-8'))

客户端

情况二,接收方的缓存机制

接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)

from socket import *
ip_port=('127.0.0.1',8080)tcp_socket_server=socket(AF_INET,SOCK_STREAM)
tcp_socket_server.bind(ip_port)
tcp_socket_server.listen(5)conn,addr=tcp_socket_server.accept()data1=conn.recv(2) #一次没有收完整
data2=conn.recv(10)#下次收的时候,会先取旧的数据,然后取新的print('----->',data1.decode('utf-8'))
print('----->',data2.decode('utf-8'))conn.close()

服务端

import socket
BUFSIZE=1024
ip_port=('127.0.0.1',8080)s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
res=s.connect_ex(ip_port)s.send('hello egg'.encode('utf-8'))

客户端

黏包的解决方案

      

struct模块

该模块可以吧一个类型,如数字,转换成固定长度的bytes

>>> struct.pack('i',1111111111111)struct.error: 'i' format requires -2147483648 <= number <= 2147483647 #这个是范围

import json,struct
#假设通过客户端上传1T:1073741824000的文件a.txt#为避免粘包,必须自定制报头
header={'file_size':1073741824000,'file_name':'/a/b/c/d/e/a.txt','md5':'8f6fbf8347faa4924a76856701edb0f3'} #1T数据,文件路径和md5值#为了该报头能传送,需要序列化并且转为bytes
head_bytes=bytes(json.dumps(header),encoding='utf-8') #序列化并转成bytes,用于传输#为了让客户端知道报头的长度,用struck将报头长度这个数字转成固定长度:4个字节
head_len_bytes=struct.pack('i',len(head_bytes)) #这4个字节里只包含了一个数字,该数字是报头的长度#客户端开始发送
conn.send(head_len_bytes) #先发报头的长度,4个bytes
conn.send(head_bytes) #再发报头的字节格式
conn.sendall(文件内容) #然后发真实内容的字节格式#服务端开始接收
head_len_bytes=s.recv(4) #先收报头4个bytes,得到报头长度的字节格式
x=struct.unpack('i',head_len_bytes)[0] #提取报头的长度

head_bytes=s.recv(x) #按照报头长度x,收取报头的bytes格式
header=json.loads(json.dumps(header)) #提取报头#最后根据报头的内容提取真实的数据,比如
real_data_len=s.recv(header['file_size'])
s.recv(real_data_len)

Socket的更多方法

服务端套接字函数
s.bind()    绑定(主机,端口号)到套接字
s.listen()  开始TCP监听
s.accept()  被动接受TCP客户的连接,(阻塞式)等待连接的到来客户端套接字函数
s.connect()     主动初始化TCP服务器连接
s.connect_ex()  connect()函数的扩展版本,出错时返回出错码,而不是抛出异常公共用途的套接字函数
s.recv()            接收TCP数据
s.send()            发送TCP数据
s.sendall()         发送TCP数据
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()        创建一个与该套接字相关的文件

更多socket方法

转载于:https://www.cnblogs.com/wangjun187197/p/9588039.html

网络编程~socket相关推荐

  1. Python网络编程(Socket)

    Python网络编程(Socket) Python提供了两个访问级别的网络服务.在一个较低的水平,您可以访问底层操作系统的基本套接字支持,允许你实现面向连接和无连接协议的客户端和服务器 Python有 ...

  2. Java网络编程 Socket、ServerSocket 详解,方法介绍及完整代码示例

    Java网络编程 Socket.ServerSocket 详解,方法介绍及完整代码示例 概念 什么是网络编程? 网络编程是指编写运行在多个设备(计算机)的程序,这些设备通过网络连接起来.当这些通过网络 ...

  3. 网络编程socket之connect函数

    网络编程socket api存在一批核心接口,而这一批核心接口就是几个看似简单的函数,尽管实际上这些函数没有一个是简单.connect函数就是这些核心接口的一个函数,它完成主动连接的过程. conne ...

  4. Python网络编程socket

    网络编程之socket 看到本篇文章的题目是不是很疑惑,what is this?,不要着急,但是记住一说网络编程,你就想socket,socket是实现网络编程的工具,那么什么是socket,什么是 ...

  5. Linux 网络编程——socket 网络编程

    文章目录 一.网络基础 TCP/UDP对比 TCP/IP协议族体系 socket IP地址 IP地址转化API inet_addr() inet_aton() inet_ntoa() inet_pto ...

  6. 树莓派 Python 网络编程 (Socket入门)

    树莓派  Python 网络编程 (Socket入门) 什么是 Socket? Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络 ...

  7. 树莓派:入门(基础配置、GPIO、网络编程 Socket)

    树莓派在创客中越来越发挥重要的作用,树莓派的强大兼用性和功能丰富,得到 DIY 朋友的青睐.带大家认识目前最新的树莓派 3B+,从零基础到入门,到动手做有趣的应用. 本场 Chat 首先会带领大家入门 ...

  8. java网络编程socket\server\TCP笔记(转)

    java网络编程socket\server\TCP笔记(转) 2012-12-14 08:30:04|  分类: Socket |  标签:java  |举报|字号 订阅 1 TCP的开销 a  连接 ...

  9. 网络编程socket之accept函数

    网络编程socket之accept函数 摘要:对于服务器编程中最重要的一步等待并接受客户的连接,那么这一步在编程中如何完成,accept函数就是完成这一步的.它从内核中取出已经建立的客户连接,然后把这 ...

  10. go net.conn读取请求头信息_go语言网络编程socket sever的实现

    首先说一下socket,网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket(百度百科). 图片来源于网络 其本质就是就是编程接口(API),对TCP.UDP的封装 ...

最新文章

  1. 伯乐:一个易用、强大的PyTorch推荐系统开源库
  2. 用上强化学习和博弈论,EA开发的测试AI成精了
  3. 中关村论坛首次设置技术交易板块,人工智能和新一代信息技术专场发布会即将召开...
  4. TypeError: sequence item 0: expected str instance, int found
  5. matlab矩阵及其基本运算—特征值分解和svd奇异值分解
  6. libjpeg-turbo(2)
  7. vscode java settings设置_兼容vscode插件的主题服务
  8. 程序员「在知乎装逼被怼」,决定用『面试』证明自己
  9. 焓湿图软件 android,焓湿图计算软件
  10. 利用VLMCSD部署本地KMS服务器(Windows + CentOS7)
  11. 安卓一些错误经验积累
  12. 马克思对“货币之谜”的 历史唯物主义解答
  13. 令人忧虑,不阅读的中国人
  14. 用python做可视化驾驶舱大屏全代码
  15. MATLAB中通用桥晶闸管的型号,基于MATLAB的电力电子技术仿真分析
  16. 使用PayPal补习注册(2/3):PayPal项目的真实注册
  17. 【阿里聚安全·安全周刊】战斗民族黑客入侵德国政府|“猫脸识别”门禁
  18. 【九天教您南方cass 9.1】 04 编码法Ⅱ绘制地形图
  19. LEARNING_CRYPTO|搭建个人以太坊测试网络+测试Solidity部署(Ganache+truffle)
  20. java+selenium+autoIt 实现下载(打印)功能

热门文章

  1. oracle里的字符串类型,Oracle中的字符串類型及相關函數詳解
  2. python和go哪个就业前景好_Python和Java就业前景对比
  3. 图档生成bin文件_「嵌入式笔记」hex文件、bin文件、axf文件的区别?
  4. java虚拟机的heap监狱_JVM垃圾回收--垃圾收集器总结
  5. TensorFlow共享变量
  6. 实现一个基础的spelling corrector
  7. 你的项目应该如何分层?
  8. GPU GEMS 3 EBOOK下载
  9. SQL Server 计算汉字笔画函数
  10. [Zeppelin]Zeppelin安装与初体验