(2)socket的基础使用(基于TCP协议)
socket()模块函数用法
基于TCP协议的套接字程序
netstart -an | findstr 8080 #查看所有TCP和UDP协议的状态,用findstr进行过滤监听8080端口
服务端套接字函数
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() #得到阻塞套接字操作的超时时间
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
socket实例:简单的服务端和客户端的通信
服务端代码
import socket 设定套接字协议标准
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #将套接字放入一个变量,这个变量名自定,但是必须要针对项目具有描述性
#socket下有一个socket类,实例化这个类括号里两个参数,套接字模块下有一个AF_INET(基于网络通信的地址家族),socket.Sock_STREAM流式协议就是TCP协议
PS:socket.SOCK_STREAM就是TCP协议,socket.SOCK_DGRAM数据包协议就是UDP协议
PS:服务端有两种套接字,这个是第一种用来绑定端口和监听端口然后做accept的 绑定端口
phone.bind(('127.0.0.1',8080)) #也是两个参数,一个是IP地址,一个是端口号,端口范围0-65535
PS:127.0.0.1这个地址就是本地回环地址,通常开发测试就用这个地址,只有本机客户端才能访问 开始运行监听端口
phone.listen(5) #一个参数就是backlog,就是指定半连接池的数量 等待syn请求
print('start....')
conn,client_addr=phone.accept() #(这个双向链接accept有2个返回值,第一个是连接对象(能收消息也能发消息),第二个是子元祖是客户端的ip和端口,以元祖的形式返回)
PS:这是第二种套接字,这个套接字就是conn,代表着tcp建好的双向通路,用来收发数据
PS:accept就是建立连接,就是去半连接池里面拿取请求 收发消息 #这个功能都是基于第二种套接字conn的
data=conn.recv(1024) #参数就一个,设定最大接收数据的字节数1024Bytes,这里设定好后要将数据放入一个变量中供后续调用
conn.send(data.upper()) #发消息,把data就是收到的消息变成大写返回
PS:收消息基于方法recv,发消息就是send 关闭conn这个套接字,就是把双向通路关闭
conn.close() #回收资源 关闭第一个套接字
phone.close() #回收资源
客户端代码
import socket 设定套接字协议类型
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
PS:客户端就一种套接字,用来收也用来发 设置发送请求的服务端地址和端口
phone.connect(('127.0.0.1',8080)) #port:0-65535 发送消息
print('连接请求已经发送')
phone.send('hello'.encode('utf-8'))#发送的请求必须是bytes类型 接收消息
data=phone.recv(1024)
print(data) 最后关闭套接字
phone.close()
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
socket实例:通信链接和循环链接
服务端代码
import socket server =socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #REUSEADDR就是重新收回利用,1就是True
PS:加上面的一条代码就可以解决端口占用问题,启动程序时候直接告诉操作系统释放端口 server.bind(('127.0.0.1',8080)) server.listen(5)
print('服务器已启动...') conn,addr = server.accept() while True: #这里的while True 用专业术语说就是通信循环
data = conn.recv(1024)
'''recv要求收的字节数必须是大于0 bytes,如果接受一个0 bytes的字节会假死,导致软件卡主'''
print('来自客户端的数据: ',data)
conn.send(data.upper()) conn.close() #如果代码结束就关闭和客户端的通信
客户端的代码
import socket client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) client.connect(('127.0.0.1',8080)) #连接服务器的地址和端口 while True: #这里的while True 就是通信循环(专业术语)
mes = input('请输入: ').strip()
if len(mes) == 0:
'''这里解决recv函数接收0比特字节的字符导致服务端死机,就是不让用户输入0比特的字节'''
print('非法输入')
continue
client.send(bytes(mes,encoding='utf-8'))
print('发送成功!') data = client.recv(1024)
print('来自服务端的信息: ',data) client.close() #如果代码结束就关闭和客户端的通信
端口占用报错:OSError: [WinError 10048] 通常每个套接字地址(协议/网络地址/端口)只允许使用一次
这个问题的出现原因就是操作系统在服务端关闭后不是立马回收资源进行端口关闭,而是等待一段时间才进行资源回收关闭端口,所以重启或者关闭后立马开始服务端会出现这个问题,
解决办法:
1、服务端换一个端口
2、服务端在绑定地址前加一条server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)代码即可
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
socket实例:当客户端单方面关闭时候导致服务端宕机报出异常的解决办法
服务端代码
import socket server =socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) server.bind(('127.0.0.1',8080)) server.listen(5) while True: #这里的while True 专业术语叫连接循环
print('等待连接中...')
conn,addr = server.accept()
print('来自客户端的连接...')
print(addr)
while True: #这里的while True 专业术语叫通信循环
try:
data = conn.recv(1024)
# if len(data) == 0:break MAC系统要加这个判断,解决客户端单方面关闭导致的循环取空的异常
print('来自客户端的数据: ',data)
conn.send(data.upper())
except Exception as f:
print(f)
break conn.close()
客户端的代码
import socket client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) client.connect(('127.0.0.1',8080)) while True: #这里的while True 专业术语就叫通信循环
mes = input('请输入: ').strip()
if len(mes) == 0:
print('非法输入')
continue
client.send(bytes(mes,encoding='utf-8'))
print('发送成功!') data = client.recv(1024)
print('来自服务端的信息: ',data) client.close()
PS:windows系统如果客户端单方面关闭在服务端会报异常,MAC系统是不会报异常,服务端而是不断的循环收取空,解决办法就是在服务端通信循环下面判断收取的数据是否为0,是0就break
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
socket实例:基于TCP协议简易版的xshell(远程实现指令控制)
服务端代码
import socket
import subprocess server =socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) server.bind(('127.0.0.1',8080)) server.listen(5) while True:
print('等待连接中...')
conn,addr = server.accept()
print('来自客户端的连接...')
print(addr)
while True:
try:
data = conn.recv(1024)
print('来自客户端的数据: ',data)
obj = subprocess.Popen(
data.decode('utf-8'), #这里将客户端的字节编码
shell = True,#这个就是调用命令解释器
stdout = subprocess.PIPE,stderr = subprocess.PIPE
)
stdouts = obj.stdout.read()
stderror = obj.stderr.read()
'''管道内获取到的结果是以字节形式存在的,所以在客户端获取到的需要编码成系统的字符格式才能正常显示'''
conn.send(stdouts + stderror) '''python中alt+enter可以实现自动导入模块'''
except Exception as f:
print(f)
break conn.close()
客户端代码
import socket client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) client.connect(('127.0.0.1',8080)) while True:
mes = input('请输入: ').strip()
if len(mes) == 0:
print('非法输入')
continue
client.send(bytes(mes,encoding='utf-8'))#发送时候需要解码成
print('发送成功!') data = client.recv(1024)
print('来自服务端的信息: ',data.decode('GBK'))#管道内的结果是以字节形式返回,读取时候需要编码成系统对应的 编码
'''管道内的结果是以字节形式,所以打印时候需要解码成字符的形式,而且编码的标准是以平台编码为准'''
client.close()
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
socket实例:基于TCP协议简易版的xshell(解决粘包问题)
须知:只有TCP有粘包现象,UDP永远不会粘包
例如基于tcp的套接字客户端往服务端上传文件,发送时文件内容是按照一段一段的字节流发送的,在接收方看了,根本不知道该文件的字节流从何处开始,在何处结束
所谓粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的
服务端代码
import socket
import struct
import subprocess server =socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) server.bind(('127.0.0.1',8080)) server.listen(5) while True:
print('等待连接中...')
conn,addr = server.accept()
print('来自客户端的连接...')
print(addr)
while True:
try:
data = conn.recv(1024)
print('来自客户端的数据: ',data)
obj = subprocess.Popen(
data.decode('utf-8'),
shell = True,
stdout = subprocess.PIPE,stderr = subprocess.PIPE
)
stdouts = obj.stdout.read()
stderror = obj.stderr.read()
total_len = len(stdouts) + len(stderror) #先计算出结果的长度 total_len = struct.pack('i',total_len) #然后用struck模块打包结果长度,注意使用的格式化标准是i,i是返回长度为4,而且值不能超过10个字符
conn.send(total_len) #将数据长度打包后发送到客户端
conn.send(stdouts + stderror) except Exception as f:
print(f)
break conn.close()
PS:struct模块详解看Python的方法和语法解释笔记
客户端代码
import socket
import struct client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) client.connect(('127.0.0.1',8080)) while True:
mes = input('请输入: ').strip()
if len(mes) == 0:
print('非法输入')
continue
client.send(bytes(mes,encoding='utf-8'))
print('发送成功!') total_len = client.recv(4) #获取服务端发来的结果长度
total_len = struct.unpack('i',total_len)[0] #将字节解包取值,因为sturct解包后是以元组形式,所以取值时候用元组取值的方法取值 recv_data = b'' #这里就是用来存放结果的
recv_len = 0 #这个是用来统计长度的
while recv_len < total_len: #如果长度等于解包后获得的长度,则循环结束,表示结果已经取完
data = client.recv(1024) #取值还是每次取1024个字节
recv_data += data #每次循环取到的值放入变量
recv_len += len(data) #每次循环取到的长度和变量相加
print('来自服务端的数据: ',recv_data.decode('gbk')) client.close()
PS:客户端在获取服务端的数据的时候,客户端设定取值的字节数,就获取服务端发来对等字节数的数据,这是一个强制对等的取值关系
PS:解决粘包问题就是让程序知道消息之间的界限,要让程序知道界限就要用到struct模块的打包和解包功能,在服务端计算出结果的总长度,通过struct模块打包成bytes类型发送给客户端,再由客户端用struct模块进行解包获取长度来判断取值
PS:struct里面的fmt格式化标准有多重,i表示打包成四个字节,l是打包成8个字节,所以可以根据需要来设定打包的标准
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
socket实例:基于TCP协议高级版的xshell
将参数等多项值放入一个字典中,然后客户端通过字典取值进行相应的操作
服务端代码
import json
import socket
import struct
import subprocess server =socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) server.bind(('127.0.0.1',8080)) server.listen(5) while True:
print('等待连接中...')
conn,addr = server.accept()
print('来自客户端的连接...')
print(addr)
while True:
try:
data = conn.recv(1024)
print('来自客户端的数据: ',data)
obj = subprocess.Popen(
data.decode('utf-8'),
shell = True,
stdout = subprocess.PIPE,stderr = subprocess.PIPE
)
stdouts = obj.stdout.read()
stderror = obj.stderr.read()
total_len = len(stdouts) + len(stderror) header_dic = {
'filename' : 'aaa.txt', #文件名称
'total_len' : total_len, #结果长度
'hash' : '123123123123' #hash值
}
header_bytes = json.dumps(header_dic) #用json模块将字典序列化
header_bytes = header_bytes.encode('utf-8') #将序列化后的字符串编码成utf-8的编码格式 header_res = struct.pack('i',len(header_bytes)) #这里打包字典的长度
conn.send(header_res) #发送字典的长度
conn.send(header_bytes) #发送序列化后的字典
conn.send(stdouts + stderror) #发送管道的内容 except Exception as f:
print(f)
break conn.close()
客户端代码
import json
import socket
import struct client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) client.connect(('127.0.0.1',8080)) while True:
mes = input('请输入: ').strip()
if len(mes) == 0:
print('非法输入')
continue
client.send(bytes(mes,encoding='utf-8'))
print('发送成功!') '''这一段定义从服务端接收字节长度,让后面的代码知道字节的分界点,不会粘包'''
header_res = client.recv(4)#客户端用的是struct模块的i标准将字典打包,这个标准就是打包成4个字节,所以这里收的时候4个字节 '''解包后长度是以元组形式存放,从元组中取得长度'''
header_len = struct.unpack('i',header_res)[0] '''这里定义客户端接收多少长度的字符,这个长度就是解包获得的'''
res = client.recv(header_len) '''这里将接收到的字节以utf-8的编码标准解码字符串'''
header_str = res.decode('utf-8') '''用json模块反序列化得到的解码字符串,获取到字典'''
header_dic = json.loads(header_str)
print(header_dic) # 打印字典 '''得到字典就可以以字典取值'''
total_len = header_dic['total_len'] recv_data = b''
recv_len = 0
while recv_len < total_len:
data = client.recv(1024)
recv_data += data
recv_len += len(data)
print('来自服务端的数据: ', recv_data.decode('gbk')) client.close()
(2)socket的基础使用(基于TCP协议)的更多相关文章
- c++下基于windows socket的多线程服务器(基于TCP协议)
之前用c++实现过基于windows socket的单线程TCP服务器(http://www.cnblogs.com/jzincnblogs/p/5170230.html),今天实现了一个多线程的版本 ...
- 基于Tcp协议的简单Socket通信实例(JAVA)
好久没写博客了,前段时间忙于做项目,耽误了些时间,今天开始继续写起~ 今天来讲下关于Socket通信的简单应用,关于什么是Socket以及一些网络编程的基础,这里就不提了,只记录最简单易懂实用的东西. ...
- 网络编程——基于TCP协议的Socket编程,基于UDP协议的Socket编程
Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服 ...
- 基于TCP协议的项目架构之Socket流传输的实现
项目背景 某银行的影像平台由于使用时间长,服务器等配置原因,老影像系统满足不了现在日益增长的数据量的需求,所以急需要升级改造.传统的影像平台使用的是Oracle数据库和简单的架构来存储数据(视频.图 ...
- 网络编程----socket介绍、基于tcp协议的套接字实现、基于udp协议的套接字实现
一.客户端/服务器架构(C/S架构) 即C/S架构,包括: 1.硬件C/S架构(打印机) 2.软件C/S架 ...
- 基于TCP协议的socket套接字编程
目录 一.什么是Scoket 二.套接字发展史及分类 2.1 基于文件类型的套接字家族 2.2 基于网络类型的套接字家族 三.套接字工作流程 3.1 服务端套接字函数 3.2 客户端套接字函数 3.3 ...
- 网络编程(二)--TCP协议、基于tcp协议的套接字socket
一.TCP协议(Transmission Control Protocol 传输控制协议) 1.可靠传输,TCP数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常TCP数据包的长度不会 ...
- 什么是 socket?简述基于 tcp 协议的套接字通信流程?
Socket的英文原义是"孔"或"插座".通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄, 可以用来实现不同虚拟机或不同计 ...
- 基于TCP 协议的socket 简单通信
DNS 服务器:域名解析 socket 套接字 : socket 是处于应用层与传输层之间的抽象层,也是一组操作起来非常简单的接口(接受数据),此接口接受数据之后,交由操作系统 为什么存在 soc ...
随机推荐
- URAL 1635 Mnemonics and Palindromes
URAL 1635 思路:区间dp+贪心,先n^2处理出每段区间是否是回文串,然后贪心地找每一段1到i的最少分割. 代码: #include<bits/stdc++.h> using na ...
- elementUI和iview兼容么
听说iview的作者居然是91年的,我要赶快加油了. https://zhuanlan.zhihu.com/p/25739512
- TortoiseXX 与TotalCommander (TC)的图标问题
TortoiseXX通过overlay图标标志文件或文件夹是否被修改等状态,非常有用. 可惜TotoalCommander上,这些图标都没有显示. 其实,只需要在TC的菜单 配置->显示-> ...
- English trip -- Review Unit1 Personal Information 个人信息
1.重点内容进行自我介绍 What's you name? I'm Loki Where are you from? I'm Local, I'm Chengdu How old are you? t ...
- (Gorails)vuejs系列视频: Webpacker/vue-resource(不再为官方推荐)。
频:https://gorails.com/episodes/using-vuejs-for-nested-forms-part-1?autoplay=1 在嵌套表格上使用vue.js. 在appli ...
- UVA-10692 Huge Mods
题目大意:计算a1^a2^a3^a4......^an模m的值. 题目解析:幂取模运算的结果一定有周期.一旦找到周期就可把高次幂转化为低次幂.有降幂公式 (a^x)%m=(a^(x%phi(m)+ph ...
- 网络编程基础——System.Net.Socket 命名空间及相关类的使用
System.Net.Socket 命名空间主要提供制作 Socket 网络应用程序的相关类.(Socket 类.TcpClient 类.TcpListener 类 和 UdpClient 类) 1. ...
- Oracle连接知识
Oracle基本连接知识 登录sys用户或 sysdba用户权限的账号 Sqlplus 建用户 Create user test identified by 12345678 ...
- 如何解决请求URL长度超过配置的maxurlLength值问题
当我们批量请求的数据太多时,会出现请求的url长度超过配置maxurllength值的问题(比如一次性操作1000条数据) 1.问题描述: 我在进行批量选择单据进行发送时,出现这个问题(批量500条) ...
- Linux WiFi Deauthenticated Reason Codes
Code Reason Explanation 0 Reserved Normal working operation 1 Unspecific Reason We don’t know what’s ...