实时在线多人聊天室

    通过流式Socket(SOCK_STREAM)来开发互动聊天室,在服务器端至少需要创建两个Socket,一个Socket专门负责接收客户端的连接请求,每次成功接收客户端的连接请求,便在服务器端创建一个对应的负责与客户端进行通信的Socket。每次成功连接一个客户端便开启一个新的线程,用于和用于处理与客户端的通信。Socket在服务器端与客户端的通信过程如下:

  1. 服务器端创建一个用于连接的Socket,并绑定一个IP地址和端口;
  2. 服务器端开启监听,等待接收客户端连接;
  3. 客户端创建一个Socket,指明服务器的IP地址和端口;
  4. 服务器端监听到客户端连接,创建一个新的用于通信的Socket与客户端建立连接并进行数据传输;
  5. 服务器端用于连接的Socket保持继续监听;

如图所示,启动服务器后,开启多个客户端进行聊天
在这里插入图片描述

服务器端
'''
gethostbyname 返回的是 主机名 的IPv4 的地址格式,如果传入的参数是IPv4 的地址格式,则返回值跟
参数一样,这个函数不支持IPv6 的域名解析。
gethostbyname_ex 则是扩展后的接口,传入主机名,它能够返回 一个三元组 (原始主机名,域名列表,
IP地址列表),这个函数同样不支持IPv6的域名解析。
'''

import socket
import threading


mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mySocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
mySocket.bind(('127.0.0.1', 5555))
mySocket.listen(128)
print('Server(%s) is listening' % socket.gethostbyname_ex('localhost')[2][0])

# 创建字典,用于存储客户端的用户
client = dict()

# 创建列表,用于存储客户端的连接
client_conn = list()

def chatMsgToOthers(exceptMe, chatMsg):
    '''把聊天消息发送给除自己以外的所有人'''
    for c in client_conn:
        if c.fileno() != exceptMe:
            try:
                # 向客户端发送消息
                c.send(chatMsg.encode())
            except:
                pass

def subThreading(client_socket, connNum):
    '''与客户端连接的子线程的处理逻辑'''
    username = client_socket.recv(1024).decode()
    client[client_socket.fileno()] = username
    client_conn.append(client_socket)
    print('client connection number:', connNum, ' has nickname:', username)
    chatMsgToOthers(connNum, '*系统提示:' + username + '已经进入聊天室,赶快和他(她)聊天吧*')
    while True:
        try:
            # 接收客户端消息
            recvedMsg = client_socket.recv(1024).decode()
            if recvedMsg:
                print(client[connNum], ':', recvedMsg)
                chatMsgToOthers(connNum, client[connNum] + ':' + recvedMsg)
        except (OSError, ConnectionResetError):
            try:
                client_conn.remove(client_socket)
            except:
                pass
            print(client[connNum], 'was exit', len(client_conn), ' person left!')
            chatMsgToOthers(connNum, "*系统提示:" + client[connNum] + '已经离开聊天室')
            client_conn.close()
            return

while True:
    connection, ip_port = mySocket.accept()
    print('Accept a new connection', connection.getsockname(), connection.fileno())
    try:
        # 接收客户端消息
        buf = connection.recv(1024).decode()
        if buf == '1':
            connection.send(b'connection success, welcome to chat room')
            myThread = threading.Thread(target=subThreading, args=(connection, connection.fileno()))
            myThread.setDaemon(True)
            myThread.start()
        else:
            # 向客户端发送消息
            connection.send(b'connection failed, please go out!')
            connection.close()
    except:
        pass

客户端
import socket
import threading

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('127.0.0.1', 5555))
# 向服务器发送连接请求
sock.send(b'1')
print(sock.recv(1024).decode())
username = input('input your username:')
# 向服务器发送聊天用户名
sock.send(username.encode())


def sendThread():
    '''向服务器端发送消息的处理逻辑'''
    while True:
        try:
            msg = input('me:')
            sock.send(msg.encode())
        except ConnectionAbortedError:
            print('Server closed this connection!')
        except ConnectionResetError:
            print('Server is closed')

def recvThread():
    '''向服务端接收消息的处理逻辑'''
    while True:
        try:
            otherMsg = sock.recv(1024)
            if otherMsg:
                print(otherMsg.decode())
            else:
                pass
        except ConnectionAbortedError:
            print('Server closed this connection')
        except ConnectionResetError:
            print('Server is closed')

send_task = threading.Thread(target=sendThread)
recv_task = threading.Thread(target=recvThread)
threads = [send_task, recv_task]

for t in threads:
    t.setDaemon(True)
    t.start()
t.join()
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值