Socket接口
Socket: Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部。
1.简单的套接字通信
服务端
import socket #1.买手机 创建一个套接字对象 phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #基于网络通信的套接字 (TCP) # print(phone) #2.绑定手机卡(ip地址) phone.bind((‘127.0.0.1‘,8080)) # 端口0-65535: 0-1024是给操作系统使用的 #3.开机 phone.listen(5) #最大挂起的链接数 #4.等电话链接 print(‘starting...‘) conn,client_addr=phone.accept() #conn 电话线 拿到可以收发信息的管道 #accept 对应客户端的connect 三次握手 #5.收,发消息 data = conn.recv(1024) #1.单位:bytes 2. 1024代表接受1024个bytes print(‘客户端的数据‘,data) conn.send(data.upper()) #6.挂电话 conn.close() #7.关机 phone.close()
客户端
import socket #1.买手机 客户端的phone 相当于服务端的conn phone=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) # print(phone) #2.拨号 (服务端的ip 和服务端的 端口) phone.connect((‘127.0.0.1‘,8080)) #0-65535: 0-1024是给操作系统使用的 #3.发收消息 bytes型 phone.send(‘hello‘.encode(‘utf-8‘)) data = phone.recv(1024) print(data) #4.关闭 phone.close()
2.加上通信循环
服务端
import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.bind((‘127.0.0.1‘,8081)) phone.listen(5) print(‘starting...‘) conn,client_addr=phone.accept() print(client_addr) while True: #通信循环 data = conn.recv(1024) print(‘客户端的数据‘,data) conn.send(data.upper()) conn.close() phone.close()
客户端
import socket phone=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) phone.connect((‘127.0.0.1‘,8081)) #0-65535: 0-1024是给操作系统使用的 while True: msg = input(‘>>: ‘).strip() phone.send(msg.encode(‘utf-8‘)) data = phone.recv(1024) print(data) phone.close()
3.C与S的bug修复
BUG问题:
1.端口的重复使用
问题:重启服务端时可能会遇到
这个是由于你的服务端仍然存在四次挥手的time_wait状态在占用地址
windows解决方法
#服务端代码 phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #SO_REUSEADDR 可以让ip端口重用 phone.bind((‘127.0.0.1‘,8080))
linux解决方法
发现系统存在大量TIME_WAIT状态的连接,通过调整linux内核参数解决, vi /etc/sysctl.conf 编辑文件,加入以下内容: net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_tw_recycle = 1 net.ipv4.tcp_fin_timeout = 30 然后执行 /sbin/sysctl -p 让参数生效。 net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭; net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭; net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。 net.ipv4.tcp_fin_timeout 修改系統默认的 TIMEOUT 时间
2.客户端关闭
服务端
import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #SO_REUSEADDR 可以让ip 端口重用 phone.bind((‘127.0.0.1‘,8080)) phone.listen(5) print(‘starting...‘) conn,client_addr=phone.accept() print(client_addr) while True: #通信循环 try: data = conn.recv(1024) # if not data:break #适用于linux操作系统 print(‘客户端的数据‘,data) conn.send(data.upper()) except ConnectionResetError:#使用于windows操作系统 break conn.close() phone.close(
客户端
客户端应用程序在发送的时候:send==空-->客户端的操作系统内存 收到为空---> 不会调用任何协议,没有发送数据给,服务端的操作系统内存
服务端应用程序在接受的时候:服务端的操作系统内存由于没有接收到数据,所以一直卡在,应用程序的recv接受过程
import socket phone=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM) phone.connect((‘127.0.0.1‘,8080)) #0-65535: 0-1024是给操作系统使用的 while True: msg = input(‘>>: ‘).strip() # msg =‘‘ if not msg:continue phone.send(msg.encode(‘utf-8‘)) #phone.send(b‘‘) # print(‘has send‘) #验证可以发空 # >>: has send data = phone.recv(1024) # print(‘has recv‘) #验证在发空的情况下 是否可以接受消息 #>>: has send print(data.decode(‘utf-8‘)) phone.close()
4.加上链接通信
服务端
客户端