一 多进程与socket结合
如果使用socket与多进程(multiprocessing)来实现数据收发同步如下代码:
if __name__ == '__main__':
p1 = multiprocessing.Process(target=read_sock, args=(tcp_socket,))
p2 = multiprocessing.Process(target=write_sock, args=(tcp_socket,))
p2.start()
p1.start()
def read_sock(tcp_socket):
str1 = input("请输入内容")
tcp_socket.send(f"{str1}".encode(encoding="utf-8"))
return str1
def write_sock(tcp_socket):
substance = tcp_socket.recv(1024).decode(encoding="utf-8")
print(substance)
则会产生报错: [WinError 10048] 通常每个套接字地址(协议/网络地址/端口)只允许使用一次。
这是因为进程之间是相互独立的,每个进程都会复制一份数据来进行运行,而套接字不允许被同时分成两份来进行使用
二 多线程与socket结合
如果使用socket与多线程(threading)来实现数据收发同步如下代码:
def read_sock(tcp_socket):
while True:
global str1
str1 = input("请输入内容")
tcp_socket.send(f"{str1}".encode(encoding="utf-8"))
print("发送成功")
if str1 == "exit":
break
return 1
def write_sock(tcp_socket):
while True:
substance = tcp_socket.recv(1024).decode(encoding="utf-8")
print("接收成功")
print(substance)
if str1 == "exit":
break
if __name__ == '__main__':
p1 = threading.Thread(target=read_sock, args=(tcp_socket,))
p2 = threading.Thread(target=write_sock, args=(tcp_socket,))
p2.setDaemon(True)
p1.start()
p2.start()
p1.join()
在使用线程的情况下,程序可以正常运行并完成收发功能
客户端效果:
服务端效果:
三 进程与线程的区别
1. 进程之间不共享全局变量
2. 线程之间共享全局变量,但是要注意资源竞争的问题,解决办法: 互斥锁
3. 创建进程的资源开销要比创建线程的资源开销要大
4. 进程是操作系统资源分配的基本单位,线程是CPU调度的基本单位
5. 线程不能够独立执行,必须依存在进程中
6. Python中多进程开发比单进程多线程开发稳定性要强
2. 线程之间共享全局变量,但是要注意资源竞争的问题,解决办法: 互斥锁
3. 创建进程的资源开销要比创建线程的资源开销要大
4. 进程是操作系统资源分配的基本单位,线程是CPU调度的基本单位
5. 线程不能够独立执行,必须依存在进程中
6. Python中多进程开发比单进程多线程开发稳定性要强
四 聊天代码展示
客户端代码:
# 导入模块
import socket
# 创建socket对象
import threading
import time
def read_sock(tcp_socket):
while True:
global str1
str1 = input()
tcp_socket.send(f"{str1}".encode(encoding="utf-8"))
print("发送成功")
if str1 == "exit":
break
return 1
def write_sock(tcp_socket):
while True:
substance = tcp_socket.recv(1024).decode(encoding="utf-8")
print(substance)
if str1 == "exit":
break
str1 = ""
ip = '192.168.22.90'
port = 7777
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_socket.connect((ip, port))
if __name__ == '__main__':
p1 = threading.Thread(target=read_sock, args=(tcp_socket,))
p2 = threading.Thread(target=write_sock, args=(tcp_socket,))
p2.setDaemon(True)
p1.start()
p2.start()
p1.join()
p2.join()
if str1 == "exit":
tcp_socket.close()
服务端代码:
# 导入模块
import socket
# 创建socket对象
import threading
def read_sock(list1):
while True:
str1 = input("请输入内容")
for li in list1:
li.send(f"{str1}".encode(encoding="utf-8"))
print("发送成功")
def write_sock(act1,list1,list_name,arr):
while True:
substance = act1.recv(1024).decode(encoding="utf-8")
print("接收成功")
if substance == "exit":
use = return_values(list_name, arr, 'seria')
list1[use].send(f"{return_values(list_name, arr, 'name')}退出聊天室".encode(encoding="utf-8"))
break
else:
for li in list1:
print(list1)
li.send(f"{return_values(list_name, arr, 'name')}说:{substance}".encode(encoding="utf-8"))
print("发送成功")
print(substance)
def return_values(list_name, arr, condition):
if condition == "name":
for num1 in range(len(list_name)):
if list_name[num1]["ip"] == arr:
return list_name[num1]["name"]
elif condition == "seria":
for num1 in range(len(list_name)):
if list_name[num1]["ip"] == arr:
return list_name[num1]["seria"]
ip = '192.168.22.90'
port = 7777
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_socket.bind((ip, port))
tcp_socket.listen(5)
list1 = []
list_name = []
while True:
act1, arr = tcp_socket.accept()
list1.append(act1)
print(f"接收到一个连接{arr}")
print(act1)
for num in range(len(list_name)):
if list_name[num]["ip"] == arr[0]:
break
else:
act1.send(f"IP{arr[0]}请输入姓名".encode(encoding="utf-8"))
substance = act1.recv(1024).decode(encoding="utf-8")
list_name.append({"ip": arr[0], "name": substance, "seria": len(list1)-1})
print(f"现有人员{list_name}")
if __name__ == '__main__':
p1 = threading.Thread(target=read_sock, args=(list1,))
p2 = threading.Thread(target=write_sock, args=(act1, list1,list_name,arr[0]))
p1.setDaemon(True)
p1.start()
p2.start()
p2.join()
act1.close()
注:客户端与服务端IP需要修改,本机测试建议改成127.0.0.1来进行测试
五 未解决问题
在客户端申请关闭连接后,再次重新运行客户端发送信息会出现报错情况,分别为以下两种错误:
[WinError 10054]一个现有的连接被远程主机强制关闭
以及:
[WinError 10038] 在一个非套接字上尝试了一个操作
该问题待后续解决