【计算机网络】Socket网络编程

实验目的

  1. 理解UDP与TCP套接字的区别
  2. 掌握UDP和TCP套接字编程方法
  3. 了解简单网络应用的编程思路
  4. 了解网络编程相关的一些库

实验环境

macos + python3

实验内容:

  1. URL 请求程序
  2. 系统时间查询
  3. 网络文件传输
  4. 网络聊天室

实验步骤:

1.URL请求程序

代码截图与文字解释:

调用requests库,可以获得url信息
r.content中包含了html内容,然后将其写入file之中

    url = input('Enter a URL: ')
    r = requests.get(url)
    # 下载网页
    with open('url_download.html', 'wb') as f:
        f.write(r.content)

还可以打印网页中的相关信息

    # 打印网页相关信息
    print('网页URL: ',r.url)
    print('网页状态码: ',r.status_code)
    print('网页编码方式: ',r.encoding)
    # print('网页内容: ',r.text)
    print('网页header:', r.headers)
    print('网页大小: {:.4} KB, {} bytes.'.format(len(r.content)/(1024), len(r.content)))

代码汇总:url_download.py

import requests

if __name__ == '__main__':
    url = input('Enter a URL: ')
    r = requests.get(url)
    # 下载网页
    with open('url_download.html', 'wb') as f:
        f.write(r.content)
    
    # 打印网页相关信息
    print('网页URL: ',r.url)
    print('网页状态码: ',r.status_code)
    print('网页编码方式: ',r.encoding)
    # print('网页内容: ',r.text)
    print('网页header:', r.headers)
    print('网页大小: {:.4} KB, {} bytes.'.format(len(r.content)/(1024), len(r.content)))
    

结果展示:

输入一个网址:

可以看到网页的相关信息,并且将网页下载下来

2.系统时间查询

代码截图与文字解释:

首先编写客户端代码:
指定服务端IP(本机localhost)以及端口(12000),并且建立TCP连接

from socket import *
serverName = 'localhost'
serverPort = 12000

print('The client is ready to connect')
print('Client is connecting to {}:{}'.format(serverName, serverPort))

# 建立TCP连接
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect((serverName, serverPort))

然后开始接受指令信息:
如果指令为非Time/Exit时,显示是非法指令
如果指令为Time/Exit时,向服务端发送指令,并且输出来自服务端的反馈;如果为Exit时,则关闭TCP连接。

while True:
    command = input('Input your command (Time / Exit):')
    
    # 指令为Time / Exit
    if command == 'Time' or command == 'Exit':
        # 向服务器发送指令
        clientSocket.send(command.encode())
        # 输出来自服务器的信息
        modifiedSentence = clientSocket.recv(1024)
        print('From Server: {}'.format(modifiedSentence.decode()))
        # 指令为EXIT时,结束TCP连接
        if command == 'Exit':
            clientSocket.close()
            break
        
    # 非法指令
    else:
        print('Invalid command')

然后编写服务端代码:
指定服务端端口为12000,并且开启监听

from socket import *
import time

serverPort = 12000
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind(('', serverPort))
serverSocket.listen(1)
print('The server is ready to connect')

建立TCP连接监听后,然后开始等待客户端的连接

while True:
    # 等待客户端连接
    print('-----------------------------------------------------')
    print('Waiting for connection...')
    
    # 接收客户端连接
    connectionSocket, addr = serverSocket.accept()
    print('Connected to {}'.format(addr))
    
    pass

建立连接后,接受来自客户端的指令
如果为Time,则返回当前时间
如果为Exit,则返回“BYE”,并关闭连接

    while True:
        # 接收客户端发送的指令,并处理指令
        command = connectionSocket.recv(1024).decode()
        
        print('Received command: {}'.format(command))
        if command == 'Time':
            returnMessage = time.asctime(time.localtime(time.time()))
        elif command == 'Exit':
            returnMessage = 'Bye'
        print('Return message: {}'.format(returnMessage))
        
        # 向客户端发送信息
        connectionSocket.send(returnMessage.encode())
        
        # 指令为EXIT时,结束TCP连接
        if command == 'Exit':
            connectionSocket.close()
            break      

代码汇总:
TCPServer.py

from socket import *
import time

serverPort = 12000
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind(('', serverPort))
serverSocket.listen(1)
print('The server is ready to connect')
while True:
    # 等待客户端连接
    print('-----------------------------------------------------')
    print('Waiting for connection...')
    
    # 接收客户端连接
    connectionSocket, addr = serverSocket.accept()
    print('Connected to {}'.format(addr))
    
    while True:
        # 接收客户端发送的指令,并处理指令
        command = connectionSocket.recv(1024).decode()
        
        print('Received command: {}'.format(command))
        if command == 'Time':
            returnMessage = time.asctime(time.localtime(time.time()))
        elif command == 'Exit':
            returnMessage = 'Bye'
        print('Return message: {}'.format(returnMessage))
        
        # 向客户端发送信息
        connectionSocket.send(returnMessage.encode())
        
        # 指令为EXIT时,结束TCP连接
        if command == 'Exit':
            connectionSocket.close()
            break

TCPClient.py

from socket import *
serverName = 'localhost'
serverPort = 12000

print('The client is ready to connect')
print('Client is connecting to {}:{}'.format(serverName, serverPort))

# 建立TCP连接
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect((serverName, serverPort))

while True:
    command = input('Input your command (Time / Exit):')
    
    # 指令为Time / Exit
    if command == 'Time' or command == 'Exit':
        # 向服务器发送指令
        clientSocket.send(command.encode())
        # 输出来自服务器的信息
        modifiedSentence = clientSocket.recv(1024)
        print('From Server: {}'.format(modifiedSentence.decode()))
        # 指令为EXIT时,结束TCP连接
        if command == 'Exit':
            clientSocket.close()
            break
        
    # 非法指令
    else:
        print('Invalid command')

结果展示:

Server端:

Client端:

只要不关闭Server端,就可以一直处理Client端的请求

3.网络文件传输

代码截图与文字解释:

首先编写客户端代码:
指定服务端IP(本机localhost)以及端口(12000),并且建立TCP连接

serverName = 'localhost'
serverPort = 12000

print('The client is ready to connect')
print('Client is connecting to {}:{}'.format(serverName, serverPort))

# 建立TCP连接
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect((serverName, serverPort))

建立连接后,服务端会发来可接受文件列表。用户通过输入文件名来选择下载的文件

msg = clientSocket.recv(1024).decode()
filenames = msg.split(',')
print('Choose a file to receive:' + '\n' + '\n'.join(filenames))

filename = input('Input the file names you want to receive:')

将需要下载的文件名发送给服务端,如果返回的信息是OK则开始下载并保存在clientData文件夹下,重命名为new+filename,否则则说明文件不存在。

filename = input('Input the file names you want to receive:')
clientSocket.send(filename.encode())

response = clientSocket.recv(1024).decode()
if response == 'OK':
    clientSocket.send('OK'.encode())
    # 准备开始接收文件
    print('Receiving the File({})...'.format(filename))
    
    # 将文件下载到本地
    f = open('clientData/new'+filename, 'wb')
    msg = clientSocket.recv(1024).decode()
    f.write(msg.encode())
    f.close()
    
    print('File({}) received.'.format(filename))
else:
    print('File({}) not found.'.format(filename))
    
clientSocket.close()
print('Client is disconnected.')

然后编写服务器端代码:
指定服务端端口为12000,并且开启监听

serverPort = 12000
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind(('', serverPort))
serverSocket.listen(1)
print('The server is ready to connect')

建立TCP连接监听后,然后开始等待客户端的连接

while True:
    # 等待客户端连接
    print('-----------------------------------------------------')
    print('Waiting for connection...')

    # 接收客户端连接
    connectionSocket, addr = serverSocket.accept()
    print('Connected to {}'.format(addr))

获得Data文件夹下的文件名,并发送给客户端进行选择’

    # 获取data文件夹下的文件名
    filenames = ''
    for filename in os.listdir('serverData'):
        filenames += filename + ','
    connectionSocket.send(filenames[:-1].encode())

接受来自客户端的申请文件名

    filename = connectionSocket.recv(1024).decode()
    print("Receiving the filename: {}.".format(filename))

根据文件名,发送文件或者错误信息

    if filename in os.listdir('serverData'):
        # 申请文件存在
        print('{} is in the data folder. ✅'.format(filename))
        connectionSocket.send('OK'.encode())
        
        print('Sending the File({})...'.format(filename))
        file = open('serverData/'+filename, "r")
        data = file.read()
        
        # 客服端准备接收文件
        msg = connectionSocket.recv(1024).decode()
        connectionSocket.send(data.encode())
        print('File({}) sent.'.format(filename))
        file.close()
    else:
        # 申请文件不存在
        print('{} is not in the data folder. ❌'.format(filename))
        connectionSocket.send('NO'.encode())
        
    connectionSocket.close()
    print(f"Connection{addr} disconnected.")

代码汇总:
TCPClient.py

from socket import *

serverName = 'localhost'
serverPort = 12000

print('The client is ready to connect')
print('Client is connecting to {}:{}'.format(serverName, serverPort))

# 建立TCP连接
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect((serverName, serverPort))

msg = clientSocket.recv(1024).decode()
filenames = msg.split(',')
print('Choose a file to receive:' + '\n' + '\n'.join(filenames))

filename = input('Input the file names you want to receive:')
clientSocket.send(filename.encode())

response = clientSocket.recv(1024).decode()
if response == 'OK':
    clientSocket.send('OK'.encode())
    # 准备开始接收文件
    print('Receiving the File({})...'.format(filename))
    
    # 将文件下载到本地
    f = open('clientData/new'+filename, 'wb')
    msg = clientSocket.recv(1024).decode()
    f.write(msg.encode())
    f.close()
    
    print('File({}) received.'.format(filename))
else:
    print('File({}) not found.'.format(filename))
    
clientSocket.close()
print('Client is disconnected.')

TCPserver.py

from socket import *
import os

serverPort = 12000
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind(('', serverPort))
serverSocket.listen(1)
print('The server is ready to connect')

while True:
    # 等待客户端连接
    print('-----------------------------------------------------')
    print('Waiting for connection...')

    # 接收客户端连接
    connectionSocket, addr = serverSocket.accept()
    print('Connected to {}'.format(addr))

    # 获取data文件夹下的文件名
    filenames = ''
    for filename in os.listdir('serverData'):
        filenames += filename + ','
    connectionSocket.send(filenames[:-1].encode())

    filename = connectionSocket.recv(1024).decode()
    print("Receiving the filename: {}.".format(filename))
    
    if filename in os.listdir('serverData'):
        # 申请文件存在
        print('{} is in the data folder. ✅'.format(filename))
        connectionSocket.send('OK'.encode())
        
        print('Sending the File({})...'.format(filename))
        file = open('serverData/'+filename, "r")
        data = file.read()
        
        # 客服端准备接收文件
        msg = connectionSocket.recv(1024).decode()
        connectionSocket.send(data.encode())
        print('File({}) sent.'.format(filename))
        file.close()
    else:
        # 申请文件不存在
        print('{} is not in the data folder. ❌'.format(filename))
        connectionSocket.send('NO'.encode())
        
    connectionSocket.close()
    print(f"Connection{addr} disconnected.")

结果展示:

首先在Data文件中存放一些文件,clientData为空

下载成功:

下载失败:(文件不存在)

4. 网络聊天室

代码截图与文字解释:

首先编写客户端代码:
建立两个线程,一个线程用于接受信息,一个线程用于发送信息

    def __init__(self, name, client_post, server_post):
        # 初始化
        self.ClientPort = client_post
        self.ServerPost = server_post
        self.udp_socket = socket(AF_INET, SOCK_DGRAM)
        self.userName = name
        self.thread_rece = Thread(target=self.recv_msg)
        self.thread_send = Thread(target=self.send_msg)

    def start(self):
        # 运行
        self.udp_socket.bind(self.ClientPort)
        data_info = self.userName+' -n'
        self.udp_socket.sendto(data_info.encode('gb2312'), self.ServerPost)
        print(self.getTime(), '系统:您已加入聊天')
        self.thread_rece.start()
        self.thread_send.start()
        self.thread_rece.join()
        self.thread_send.join()

接受信息:
接受来自服务端发送的信息,如果为exit则关闭TCP连接,否则展示信息。

    def recv_msg(self):
        # 接收信息
        while True:
            recv_data, dest_ip = self.udp_socket.recvfrom(
                1024)  # 1024 表示接收最大字节  防止内存溢出

            if recv_data.decode("gb2312") == 'exit' and dest_ip == self.ServerPost:
                print(self.getTime(), '客户端已退出')
                self.udp_socket.close()
                break
            print(recv_data.decode("gb2312"))

发送信息:
根据输入,发送信息给服务端

    def send_msg(self):
        # 发送信息
        while True:
            data_info = input()
            self.udp_socket.sendto(data_info.encode('gb2312'), self.ServerPost)
            if data_info == 'exit':
                break

辅助函数:(返回时间)

    def getTime(self):
        # 返回时间
        return '['+time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())+']'

然后编写服务端代码:
准备以下数据结构记录相关信息

    user_name = {}		# dict 用户名:ip地址
    user_ip = {}		# dict ip地址:用户名
    __ServerOpen = True     # 服务器开关

建立两个线程,一个线程用于接受信息,一个线程用于发送信息

        self.thread_rece = Thread(target=self.recv_msg)
        self.thread_send = Thread(target=self.send_msg)

    def start(self):
        print(self.getTime(), '服务端已启动')
        self.thread_rece.start()
        self.thread_send.start()
        self.thread_rece.join()
        self.thread_send.join()
  1. 添加用户
    向所有服务端发送新用户加入的信息,并将IP与用户名加入user_name, user_ip中
                data_info = self.getTime()+' 系统:'+info_list[0] + '加入了聊天'
                self.sent_to_all(data_info)
                self.user_name[info_list[0]] = dest_ip
                self.user_ip[dest_ip] = info_list[0]
  1. 发送信息函数
    除了直接使用socket.send,还定义了两个其它函数
    向非自身客户端发送信息:(用户A发送信息,其他客户端获得信息内容)
    # 向所有用户发送消息
    def sent_to_all_notMe(self, name, data_info):
        # 广播消息除了指定用户
        for i in self.user_name.keys():
            if i != name:
                self.udp_socket.sendto(
                    data_info.encode('gb2312'), self.user_name[i])

向所有客户端发送信息:(系统广播)

    # 向所有用户发送消息
    def sent_to_all(self, data_info):
        for i in self.user_ip.keys():
            self.udp_socket.sendto(data_info.encode('gb2312'), i)
  1. 信息处理:
    接受来自客户端的信息,并根据信息判断接下来的操作
        # 接收信息
        while True:
            recv_data, dest_ip = self.udp_socket.recvfrom(
                1024)  # 1024 表示接收最大字节  防止内存溢出

这里我定义了三种信息格式:
message -t name: 发送信息message给name(类似私聊)
message -ta: 将信息message群发给当前聊天室中所有成员
exit: 退出聊天室

因此在收到信息后,我们需要首先对信息进行解析,确认信息为哪一种格式

info_list = str(recv_data.decode("gb2312")).split(' ')  # 切割命令

① message -t name

            # 向指定用户发送私聊
            elif info_list[-2] == '-t':
                if info_list[-1] not in self.user_name.keys():  # 目前查询不到目标用户,向发送用户发起警告
                    data_info = self.getTime()+' 系统:发送失败!用户不存在!'
                    self.udp_socket.sendto(data_info.encode('gb2312'), dest_ip)
                    continue
                dest_port = self.user_name[info_list[-1]]  # 接收方端口
                data_info = self.getTime(
                )+' %s:' % self.user_ip[dest_ip]+' '.join(info_list[:-2])  # 需发送的信息
                self.udp_socket.sendto(data_info.encode('gb2312'), dest_port)

② message -ta

            # 向所有用户发送消息
            elif info_list[-1] == '-ta':
                name = self.user_ip[dest_ip]
                data_info = self.getTime()+' %s:' % name + \
                    ' '.join(info_list[:-1])
                self.sent_to_all_notMe(name, data_info)

③ exit

            # 用户退出聊天室
            if str(recv_data.decode("gb2312")) == 'exit':
                self.udp_socket.sendto('exit'.encode('gb2312'), dest_ip)
                name = self.user_ip.pop(dest_ip)
                self.sent_to_all(self.getTime()+' 系统:%s已退出聊天' % name)
  1. 关闭聊天室
    使用__ServerOpen记录聊天室的启动情况
    如果服务器关闭,则会首先想所有聊天室发送聊天室关闭的提示
    def send_msg(self):
        while self.__ServerOpen:
            data_info = input()
            if data_info == 'exit':
                self.__ServerOpen = False
                print(self.getTime(), '服务端关闭中,等待所有用户下线')
                self.sent_to_all(self.getTime()+' 服务器系统已关闭,请自行下线')
                break

然后等待所有客户端都退出聊天室后,在关闭连接。

            # 服务器关闭后就停止接收客户端信息,等待所有用户退出
            if not self.__ServerOpen:
                self.udp_socket.sendto('exit'.encode('gb2312'), dest_ip)
                # 从用户列表中删除用户
                name = self.user_ip.pop(dest_ip)
                self.sent_to_all(self.getTime()+' 系统:%s已退出聊天' % name)
                
                # 等待所有用户退出聊天室
                while len(self.user_ip):
                    recv_data, dest_ip = self.udp_socket.recvfrom(1024)
                    self.udp_socket.sendto('exit'.encode('gb2312'), dest_ip)
                    
                    # 从用户列表中删除用户
                    name = self.user_ip.pop(dest_ip)
                    self.sent_to_all(self.getTime()+' 系统:%s已退出聊天' % name)
                    
                # 关闭聊天室
                print(self.getTime(), '服务端已关闭')
                self.udp_socket.close()
                break

代码汇总:
server.py

from socket import *
from threading import Thread
import time


class Server():

    user_name = {}		# dict 用户名:ip地址
    user_ip = {}		# dict ip地址:用户名
    __ServerOpen = True     # 服务器开关

    def __init__(self, post):

        self.ServerPort = post
        self.udp_socket = socket(AF_INET, SOCK_DGRAM)
        # 服务器端口
        self.udp_socket.bind(self.ServerPort)
        self.thread_rece = Thread(target=self.recv_msg)
        self.thread_send = Thread(target=self.send_msg)

    def start(self):
        print(self.getTime(), '服务端已启动')
        self.thread_rece.start()
        self.thread_send.start()
        self.thread_rece.join()
        self.thread_send.join()

    def recv_msg(self):

        # 接收信息
        while True:
            recv_data, dest_ip = self.udp_socket.recvfrom(
                1024)  # 1024 表示接收最大字节  防止内存溢出

            # 服务器关闭后就停止接收客户端信息,等待所有用户退出
            if not self.__ServerOpen:
                self.udp_socket.sendto('exit'.encode('gb2312'), dest_ip)
                # 从用户列表中删除用户
                name = self.user_ip.pop(dest_ip)
                self.sent_to_all(self.getTime()+' 系统:%s已退出聊天' % name)
                
                # 等待所有用户退出聊天室
                while len(self.user_ip):
                    recv_data, dest_ip = self.udp_socket.recvfrom(1024)
                    self.udp_socket.sendto('exit'.encode('gb2312'), dest_ip)
                    
                    # 从用户列表中删除用户
                    name = self.user_ip.pop(dest_ip)
                    self.sent_to_all(self.getTime()+' 系统:%s已退出聊天' % name)
                    
                # 关闭聊天室
                print(self.getTime(), '服务端已关闭')
                self.udp_socket.close()
                break

            print(self.getTime(), dest_ip, recv_data)
            info_list = str(recv_data.decode("gb2312")).split(' ')  # 切割命令
            
            # 用户退出聊天室
            if str(recv_data.decode("gb2312")) == 'exit':
                self.udp_socket.sendto('exit'.encode('gb2312'), dest_ip)
                name = self.user_ip.pop(dest_ip)
                self.sent_to_all(self.getTime()+' 系统:%s已退出聊天' % name)
                
            # 向指定用户发送私聊
            elif info_list[-2] == '-t':
                if info_list[-1] not in self.user_name.keys():  # 目前查询不到目标用户,向发送用户发起警告
                    data_info = self.getTime()+' 系统:发送失败!用户不存在!'
                    self.udp_socket.sendto(data_info.encode('gb2312'), dest_ip)
                    continue
                dest_port = self.user_name[info_list[-1]]  # 接收方端口
                data_info = self.getTime(
                )+' %s:' % self.user_ip[dest_ip]+' '.join(info_list[:-2])  # 需发送的信息
                self.udp_socket.sendto(data_info.encode('gb2312'), dest_port)

            # 新用户注册
            elif info_list[-1] == '-n':
                data_info = self.getTime()+' 系统:'+info_list[0] + '加入了聊天'
                self.sent_to_all(data_info)
                self.user_name[info_list[0]] = dest_ip
                self.user_ip[dest_ip] = info_list[0]
                
            # 向所有用户发送消息
            elif info_list[-1] == '-ta':
                name = self.user_ip[dest_ip]
                data_info = self.getTime()+' %s:' % name + \
                    ' '.join(info_list[:-1])
                self.sent_to_all_notMe(name, data_info)
                
    # 向所有用户发送消息
    def sent_to_all(self, data_info):
        for i in self.user_ip.keys():
            self.udp_socket.sendto(data_info.encode('gb2312'), i)

    # 向所有用户发送消息
    def sent_to_all_notMe(self, name, data_info):
        # 广播消息除了指定用户
        for i in self.user_name.keys():
            if i != name:
                self.udp_socket.sendto(
                    data_info.encode('gb2312'), self.user_name[i])

    def getTime(self):
        return '['+time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())+']'

    def send_msg(self):
        while self.__ServerOpen:
            data_info = input()
            if data_info == 'exit':
                self.__ServerOpen = False
                print(self.getTime(), '服务端关闭中,等待所有用户下线')
                self.sent_to_all(self.getTime()+' 服务器系统已关闭,请自行下线')
                break


if __name__ == '__main__':
    server1 = Server(('127.0.0.1', 12000))
    server1.start()

client.py

from socket import *
from threading import Thread
import time


class Client():

    def __init__(self, name, client_post, server_post):
        # 初始化
        self.ClientPort = client_post
        self.ServerPost = server_post
        self.udp_socket = socket(AF_INET, SOCK_DGRAM)
        self.userName = name
        self.thread_rece = Thread(target=self.recv_msg)
        self.thread_send = Thread(target=self.send_msg)

    def start(self):
        # 运行
        self.udp_socket.bind(self.ClientPort)
        data_info = self.userName+' -n'
        self.udp_socket.sendto(data_info.encode('gb2312'), self.ServerPost)
        print(self.getTime(), '系统:您已加入聊天')
        self.thread_rece.start()
        self.thread_send.start()
        self.thread_rece.join()
        self.thread_send.join()

    def recv_msg(self):
        # 接收信息
        while True:
            recv_data, dest_ip = self.udp_socket.recvfrom(
                1024)  # 1024 表示接收最大字节  防止内存溢出

            if recv_data.decode("gb2312") == 'exit' and dest_ip == self.ServerPost:
                print(self.getTime(), '客户端已退出')
                self.udp_socket.close()
                break
            print(recv_data.decode("gb2312"))

    def send_msg(self):
        # 发送信息
        while True:
            data_info = input()
            self.udp_socket.sendto(data_info.encode('gb2312'), self.ServerPost)
            if data_info == 'exit':
                break

    def getTime(self):
        # 返回时间
        return '['+time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())+']'


if __name__ == '__main__':
    Postnum = int(input('我方使用端口号: '))
    name = input('我方用户名: ')
    client = Client(name, ('127.0.0.1', Postnum), ('127.0.0.1', 12000))
    client.start()

结果展示:

首先展示群发功能
这是每个客户端的界面展示,可以看见每个用户都向聊天室发送了一条消息,并成功展示



下方是服务器端的界面展示

然后展示私聊功能
成功:user1向user2发送私聊消息,user3的界面中不会有信息展示



失败:user1向user4发送私聊消息,发现没有该用户

接着随机发送一些消息,并关闭聊天室服务器



服务端:
最后发送exit指令,提示所有用户下线。并且在所有用户下线后,自动结束进程

你可能感兴趣的:(计算机网络,计算机网络,socket)