在学socket有时候我们会遇到这种问题:
解决方法一:
在服务端中加入:severTCP.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
#!/urs/bin/evn python
# -*- coding:utf-8 -*-
import socket
severTCP = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
severTCP.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
severTCP.bind(("127.0.0.1", 8888)) # 绑定端口
severTCP.listen(5) # 监听
print("starting....")
client, address = severTCP.accept() # 等待连接
while True: # 通信循环
data = client.recv(1024) # 单位:byte. 1024代表最大接收1024个byte,收数据
print("来%s客服端的数据" % client, data.decode("utf-8"))
client.send(data.upper()) # 发数据
client.close()
severTCP.close()
方法二:
发现系统存在大量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 时间
客户端发送空,卡住,主要是在原因:缓冲区为空,recv就卡住:
服务端:
#!/urs/bin/evn python
# -*- coding:utf-8 -*-
import socket
clientTCP = socket.socket(socket.AF_INET,
socket.SOCK_STREAM)
clientTCP.connect(("127.0.0.1", 8888))
while True:
msg = input(">>:").strip()
if not msg:continue
# if len(msg)==0:continue
clientTCP.send(msg.encode("utf-8"))
data = clientTCP.recv(1024)
print(data.decode("utf-8"))
clientTCP.close()
结果:
客户端
服务端:
当客户端异常断开连接,看见服务端:
Liunx :
#!/urs/bin/evn python
# -*- coding:utf-8 -*-
import socket
severTCP = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
severTCP.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
severTCP.bind(("127.0.0.1", 8888)) # 绑定端口
severTCP.listen(5) # 监听
print("starting....")
client, address = severTCP.accept() # 等待连接
while True: # 通信循环
data = client.recv(1024) # 单位:byte. 1024代表最大接收1024个byte,收数据
if not data: break # 针对Liunx
# if len(data): break
print("来%s客服端的数据" % client, data.decode("utf-8"))
client.send(data.upper()) # 发数据
client.close()
severTCP.close()
windows:
#!/urs/bin/evn python
# -*- coding:utf-8 -*-
import socket
severTCP = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
severTCP.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
severTCP.bind(("127.0.0.1", 8888)) # 绑定端口
severTCP.listen(5) # 监听
print("starting....")
client, address = severTCP.accept() # 等待连接
while True: # 通信循环
try:
data = client.recv(1024) # 单位:byte. 1024代表最大接收1024个byte,收数据
print("来%s客服端的数据" % client, data.decode("utf-8"))
client.send(data.upper()) # 发数据
except ConnectionResetError:
break
client.close()
severTCP.close()
结果:
客户端
服务端:
实现服务端对多个客户端服务(但这没有并发结果)
#!/urs/bin/evn python
# -*- coding:utf-8 -*-
import socket
severTCP = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
severTCP.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
severTCP.bind(("127.0.0.1", 8888)) # 绑定端口
severTCP.listen(5) # 监听
print("starting....")
while True:
client, address = severTCP.accept() # 等待连接
while True: # 通信循环
try:
data = client.recv(1024) # 单位:byte. 1024代表最大接收1024个byte,收数据
if not data:break # Liunx
print("来%s客服端的数据" % client, data.decode("utf-8"))
client.send(data.upper()) # 发数据
except ConnectionResetError:
break
client.close()
severTCP.close()
一个简单聊天功能:
服务端:
#!/urs/bin/env python
# -*- coding:utf-8 -*-
import socket
sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock_server.bind(("127.0.0.1", 8888))
sock_server.listen(1) # 开始监听,1代表在允许有一个连接排队,更多的新连接连进来时就会被拒绝
while True:
conn, addr = sock_server.accept() # 阻塞直到有连接为止,有了一个新连接进来后,就会为这个请求生成一个连接对象
print("新人来了", conn.getpeername())
with conn:
print('Connected by', addr)
while True:
try:
data = conn.recv(1024) # 接收1024个字节
print("recv from zq:", conn.getpeername(), data.decode())
if not data: break # 收不到数据,就break
response = input(">>>").strip()
conn.send(response.encode("utf-8"))
#print("send to xqx:", response)
except ConnectionResetError:
break
conn.close()
sock_server.close()
客户端:
#!/urs/bin/evn python
# -*- coding:utf-8 -*-
import socket
clientTCP = socket.socket(socket.AF_INET,
socket.SOCK_STREAM)
clientTCP.connect(("127.0.0.1", 8888))
while True:
msg = input(">>:").strip()
if not msg:continue
# if len(msg)==0:continue
clientTCP.send(msg.encode("utf-8"))
data = clientTCP.recv(1024)
print('xqx',data.decode("utf-8"))
clientTCP.close()
结果:
客户端
服务端
文件传输:
#! /urs/bin/evn python # -*- coding:utf-8 -*- import socket import struct import json phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # tcp协议 # 链接服务端 phone.connect(("127.0.0.1", 8083)) # 发,收消息 while True: # 1 发命令 cmd = input(">>>:").strip() if not cmd:continue phone.send(cmd.encode("utf-8")) # 发 # 2 以写的方式打开一个新文件,接收服务端发来的文件的内容写入客户端 # 第一步:先收报头长度 obj = phone.recv(4) header_size = struct.unpack("i", obj)[0] # 第二步:再收报头 header_bytes = phone.recv(header_size) # 第三步:从报头中解析出对真实数据的描述信息(数据的长度) header_json = header_bytes.decode("utf-8") heade_dic = json.loads(header_json) print(heade_dic) total_size = heade_dic["file_size"] # 第四步:接收真实数据 filename = heade_dic["filename"] with open(filename, "wb") as f: recv_size = 0 while recv_size < total_size: line = phone.recv(1024) # 收。接命令 f.write(line) recv_size += len(line) # 关闭 phone.close()
#! /urs/bin/evn python # -*- coding:utf-8 -*- import socket import struct import json import os phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # tcp协议 phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 绑定ip和端口 phone.bind(("127.0.0.1", 8083)) # 监听 phone.listen(5) print("statting....") # 等待链接 while True: # 链接循环。这里暂时没有并发功能 conn, client_add = phone.accept() # 这一步对应客服端connect print(client_add) while True: # 通信循环 try: # 1 收命令 res = conn.recv(8192) # 单位:byte. 1024代表最大接收1024个byte if not res: break # 针对异常后(liunx客服端强行停机后,服务端进入死循环,只适用Linux) # print("客服端的数据", cmd) # 2 解析命令。提取相应命令参数 cmds = res.decode("utf-8").split() filename = cmds[1] # 以读的方式打开文件。读取文件内容发送给客服端 # 第一步:制作固定长度的报头 heade_dic = { "filename": filename, "md5": "xxxx", "file_size": os.path.getsize(filename) } heade_json = json.dumps(heade_dic) header_bytes = heade_json.encode("utf-8") # 第二步:先发送报头的长度 conn.send(struct.pack("i", len(header_bytes))) # 第三步:再发报头 # print(len(stdout) + len(stderr)) conn.send(header_bytes) # conn.send(str(total_size).encode("utf-8")) # 第四步:再发真实的数据 with open(filename, "rb") as f: for line in f: conn.send(line) except ConnectionResetError: # 适用window操作系统 break conn.close() phone.close()