关于socket收发信息与多线程,多进程问题总结

一  多进程与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中多进程开发比单进程多线程开发稳定性要强

四  聊天代码展示

客户端代码:

# 导入模块
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] 在一个非套接字上尝试了一个操作

该问题待后续解决

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值