Python实现聊天室全双工通信

本文分享了使用TCPSocket实现聊天室的过程,包括多线程处理、连接管理和异常处理等关键技术点。作者通过设计接收新连接和消息转发的线程,解决了recv阻塞问题,并实现了客户端连接超时处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

学校的作业,用TCPSocket实现聊天室,课程中的只是简单的一对一对话,网上有用IO多路复用select的,有多线程的。

多线程的想过,服务器为每一个客户机开一个线程,很好实现但开销太大,我当初设计的是接收新连接线程和接收新消息并转发线程,存活连接用list保存。

遇到的问题是recv阻塞问题,解决方法是设置客户端连接超时,无消息则捕获timeout异常并pass,继续处理其他连接的缓冲区。(吐槽:python还是把异常作为正常流程处理了,作为一个java基础的开发还是很难接受的),本来已经写完了,用网络测试工具做客户机总是无法断开连接,甚至能继续发消息,后来发现要把窗口叉掉才能断开,那断开按钮还有什么意义,坑啊。

以下代码

服务器:

#coding=utf-8
from threading import Thread
from socket import *
import time

tcpSocket = None
aliveConnList = []

#接受新连接线程
def acceptConn():
    global aliveConnList
    global tcpSocket
    while True:
        newSocket,clientAddr = tcpSocket.accept()
        print('%s已连接'%(str(clientAddr)))
        newSocket.settimeout(1)
        aliveConnList.append((newSocket,clientAddr))

#接收新消息线程
def recvData():
    global aliveConnList
    while True:
        #遍历缓冲区,有数据输出并转发,没数据超时过
        for s in aliveConnList:
            try:
                print("recving")
                recvData = s[0].recv(1024)
                print("received")
                if len(recvData)>0:
                    #有数据,向其他tcp发送该数据
                    for other in aliveConnList:
                        if other!=s:
                            other[0].send(('recv from %s:%s'%(s[1],recvData)).encode())
                    print('recv from %s:%s'%(s[1],recvData))
                else:
                    #客户端断开
                    print('%s已断开连接'%(str(s[1])))
                    s[0].close()
                    aliveConnList.remove(s)
            except timeout:
                #该连接无数据
                pass
        #可怜的cpu
        time.sleep(1)

def main():
    global tcpSocket
    tcpSocket = socket(AF_INET,SOCK_STREAM)
    address = ('',1234)
    tcpSocket.bind(address)
    tcpSocket.listen(5)

    print("欢迎使用")

    ta = Thread(target=acceptConn)
    tr = Thread(target=recvData)

    ta.start()
    tr.start()

    ta.join()
    tr.join()

    tcpSocket.close()

if __name__ == "__main__":
    main()

 

客户端:

from threading import Thread
from socket import *
import time

tcpClientSocket = None

#接收服务器数据
def recvData():
    global tcpClientSocket
    while True:
        recvData = tcpClientSocket.recv(1024)
        if len(recvData)==0:
                print('服务器已关闭!')
                tcpClientSocket.close()
                break        
        print(recvData)
        time.sleep(1)

#发送数据
def sendData():
    global tcpClientSocket
    while True:
        sendData = input("")
        tcpClientSocket.send(sendData.encode())

def main():
    global tcpClientSocket
    tcpClientSocket = socket(AF_INET,SOCK_STREAM)
    serverIP = input("请输入服务器ip: ")
    serverPort = input("请输入服务器端口号: ")
    serverAdd = (serverIP,int(serverPort))
    tcpClientSocket.connect(serverAdd)

    tr = Thread(target=recvData)
    ts = Thread(target=sendData)

    tr.start()
    ts.start()

    tr.join()
    ts.join()

    tcpClientSocket.close()

if __name__ == "__main__":
    main()

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值