Python网络通信编程总结

  • 实现双向通信
import socket
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind((‘0.0.0.0‘,8002))
server.listen()
print(‘server 已经启动,欢迎连接‘)
sock,addr = server.accept()
while True:          #使用循环实现服务器端永久等待消息
    data=socl.recv(1024)
    print(data.decode())
    if data.decode()==‘exit‘:       #如果客户端发来exit,就断开连接,判断语句要放在接收到客户端消息后,立刻执行,否则,不起作用。
        break    
    send_to_client=input()        #输入发送给客户端的消息
    sock.send(send_to_client.encode())
server.close()                           #关闭客户端连接
sock.close()                              #关闭sock连接
#上述代码为服务器端代码
#以下代码是客户端代码
import socket
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect((‘127.0.0.1‘,8002))
while True:
    send_to_server = input()
    client.send(send_to_server.encode())
    data = client.recv(1024)
    print(data.decode())
    if data.decode()==‘exit‘:
        break
client.close()

以上代码只能实现一个客户端和服务器通信。要实现多个客户端和服务器通信,就需要使用线程。把每个客户端和服务器的连接都当做是一个线程,这样,线程之间互不干扰,顺利运行。

import socket
import threading
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind((‘0.0.0.0‘,8002))
server.listen()
print(‘server 已经启动,欢迎连接‘)
def handle_client(sock):           #定义函数,线程执行体
    while True:                #每一个线程和服务器的通信都是多次
    data = sock.recv(1024)
    print(data.decode())
    send_to_client = input()
    sock.send(send_to_client.encode())
while True:              #服务器不知道客户端连接的数量,所以依然使用循环    
    sock,addr=server.accept()       #服务器连接到了一个客户端
    threading.Thread(target=handle_client,args=(sock,)).start()  #启动一个线程执行和客户端的交互

在使用线程实现了多个客户端和服务器之间的通信后。

要实现群聊的功能,就把服务器当做一个转发机构,专门转发各种客户端发来的信息。

由于在客户端中input方法输入发送数据,而该方法是一个阻塞方法,必须先输入再发送。所以也可把客户端的接收,发送看做是一种线程,发送接收互不干扰。

在群聊中,设置客户端标识,方便所有客户端明确信息从哪里发出。

关闭某个客户端后,服务器不会报错,需要异常处理机制。

import socket
import threading
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind((‘0.0.0.0‘,8004))
server.listen()
print(‘server 已经启动,欢迎连接‘)
client_sockets = []
def handle_client(sock):     #服务器转发数据,定义客户端标识,处理客户端退出异常
    try:              #处理某个客户端退出的异常
        username=sock.recv(1024).decode()      #接收客户端标识
        for client in client_sockets:      #发送消息说明每个客户端加入群聊
            client.send((‘欢迎【‘+username+‘】加入群聊‘).encode())
        while True:        #接收客户端标识后,开始接收客户端消息
            data=sock.recv(1024).decode()     #接收客户端标识
            if len(client_sockets)>0:      #客户端列表中国如果有客户,向每个客户端发送消息
                for client in client_sockets:
                    client.send((username+‘说:‘+data).encode())
    except Exception as e:
        client_socket.remove(sock)           #出现客户端退出群聊,服务器出现异常,删掉该连接
        for client in clietn_sockets:   #向每个客户端发送某客户端退出群聊
            client.send((username+‘已退出群聊‘).encode())  
while True:      #循环出现多个客户端连接
    sock,addr= server.accept()
    client_sockets.append(sock)      
    sock.send(‘欢迎加入群聊,请输入您的昵称:‘.encode())
    threading.Thread(target=handle_client,args=(sock,)).start()  #启动服务器连接客户端
#上述是实现群聊的完全代码
#以下是客户端代码
import socket
import threading
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect((‘127.0.0.1‘,8004))
def receive(client):
    while True:
        print(client.recv(1024).decode())
def sendto(client):
    while True:
        send_to_other_client = input()
        client.send(send_to_other_client.encode())
threading.Thread(target=receive,args=(client,)).start()
threading.Thread(target=sendto,args=(client,)).start()

在群聊的基础上,实现私聊。需要使用字典数据类型存储每个客户端的连接和输入的昵称名。

客户端的代码不需要做出改变。

import socket
import threading
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind((‘0.0.0.0‘,8004))
server.listen()
print(‘server 已经启动,欢迎连接‘)
client_sockets = {}  #使用字典数据类型,存放连接和输入昵称之间的映射
def handle_client(sock):      #处理私聊
    try:    #处理私聊,某客户端退出群聊异常不能缺失
        username=sock.recv(1024).decode()    #获取输入昵称
        client_sockets[sock]=username   #连接和输入昵称相互匹配
        for client in client_sockets.keys():
            client.send((‘欢迎【‘+username+‘】加入群聊‘).encode())
        while True:     #客户端输入循环
            data=sock.recv(1024).decode()   #服务器接受了客户端昵称后,再接受信息
            send_data = ‘【‘+username+‘】说:‘+data
            if data.startswith(‘@‘):           #处理私聊,私聊以@开头
                msg=data.split(‘ ‘)             #分割输入信息,
                private_name=msg[0][1:]      #获取输入昵称
                for k,v in client_sockets.items():  #遍历映射,查找符合的昵称
                    if v==private_name:      #找到符合的用户昵称
                        k.send(send_data.encode())   #向该昵称的连接发生私聊信息
            else:     #不是私聊,就是普通群聊
                if len(client_sockets)>0:
                    for client in client_sockets.keys():  #依次遍历各个连接
                        client.send(send_data.encode())
    exception Exception as e:
        client_sockets.pop(sock)     #出现异常,删除连接
        for client in client_sockets.keys():
            client.send((username+‘已退出群聊‘).encode())
while True:         #客户端连接未知
    sock,addr=server.accept()
    client_sockets[sock]=‘‘
    sock.send(‘欢迎您加入群聊,请输入您的昵称:‘.encode())
    threading.Thread(target=handle_client,args=(sock,)).start()   #启动服务器,连接客户端

相关推荐