天天看点

Python-socket网络编程(二)--基于 TCP实现聊天功能

Python-socket网络编程(二)–基于 TCP实现聊天功能

在Python-socket网络编程(一)中介绍的socket的基本使用

在了解了基本使用后,考虑实现一个点到点的小聊天工具

基本思路:

服务器:用来监听客户端,当客户端发送消息时,接收客户端消息并显示,同时发送消息给客户端

客户端:连接服务器,发送消息给服务器,并接收服务器返回的消息

TCP服务器代码:

from socket import *
from time import ctime


# 地址和端口
HOST = ''
PORT = 21567
BUFFER_SIZE = 1024

ADDR = (HOST, PORT)


tcp_socket_server = socket(AF_INET, SOCK_STREAM)  # 创建服务器套接字
tcp_socket_server.bind(ADDR)  # 套接字与地址绑定
tcp_socket_server.listen(5)  # 监听连接, 其中参数为最大等待数

# 服务器无限循环等待连接
while True:
    print('waiting for connection....')
    tcp_client_server, addr = tcp_socket_server.accept()  # 接受客户端连接
    print('... connect from: ', addr)
    # 通信循环
    while True:
        data = tcp_client_server.recv(BUFFER_SIZE)  # 接受客户端发送的消息
        print('客户端消息:', data.decode('utf-8'))
        if not data:
            break
        message = input('> ')
        
        tcp_client_server.send(message.encode('utf-8'))  # 客户端发送消息
        
    tcp_client_server.close()  # 关闭客户端套接字

tcp_socket_server.close()  # 关闭服务器套接字(可选)

           

TCP客户端代码:

from socket import *

HOST = '127.0.0.1'
PORT = 21567
PORT2 = 6666
BUFFER_SIZE = 1024

ADDR = (HOST, PORT)

tcp_client_server = socket(AF_INET, SOCK_STREAM)  # 创建客户端套接字
tcp_client_server.bind((HOST, PORT2))
tcp_client_server.connect(ADDR)  # 尝试连接服务器
address = tcp_client_server.getsockname()  # 返回当前套接字的地址
print('当前套接字的地址:', address)


# 通信循环
while True:
    msg = input("> ")
    # if msg == "quit":
    #     break
    # data = str({"msg": msg, "target_address": ('127.0.0.1', 7777), "owner_address": address})
    tcp_client_server.send(msg.encode('utf-8'))  # 客户端发送消息

    rev_data = tcp_client_server.recv(BUFFER_SIZE)  # 客户端接受消息
    if not rev_data:
        break

    print('服务器消息:', rev_data.decode('utf-8'))

tcp_client_server.close()  # 关闭客户端连接
           

运行发现,可以实现基本的收发功能,但是会发现,当客户端发送消息后,就会处于阻塞状态,持续等待服务器返回消息,同样服务器也是如此。而且这两段代码实现的只是客户端和服务器两点之间的通信,效果不是很理想。做个简单的升级。

升级思路:

服务器:

  • 能够支持两个客户端进行通信
  • 负责转发两个客户端之间的消息

客户端:

  • 通过服务器向指定客户端发送消息

代码如下:

TCP服务器

from socket import *
from threading import Thread


HOST = ''
PORT = 21567
BUFFER_SIZE = 1024

ADDR = (HOST, PORT)

# 连接池
g_conn_pool = dict()


def accept_link():
    """
    接受连接,并且处理消息转发
    :return:
    """
    while True:
        print('wait connection....')
        client, addr = tcp_server_socket.accept()
        g_conn_pool[addr] = client
        print(f'client {addr} connect')
        thread = Thread(target=message_handler, args=(client, addr))
        thread.setDaemon(True)
        thread.start()


def message_handler(client, addr):
    """
    消息转发的逻辑
    :param client:
    :param addr:
    :return:
    """
    while True:
        data = client.recv(BUFFER_SIZE).decode('utf-8')
        print(f'客户端 {addr} 发送的消息:', data)

        data_dict = eval(data)
        message = data_dict['msg']
        addr = data_dict['target_address']
        send_addr = data_dict['owner_address']
        send_handler(g_conn_pool[addr], send_addr, message)


def send_handler(client, send_addr, message):
    print("发送消息")
    client.send(b'%s: %s' % (str(send_addr).encode('utf-8'), message.encode('utf-8')))  # 客户端发送消息


if __name__ == '__main__':
    tcp_server_socket = socket(AF_INET, SOCK_STREAM)
    tcp_server_socket.bind(ADDR)
    tcp_server_socket.listen(5)
    accept_link()
           

TCP客户端1 代码:

from socket import *
from threading import Thread


HOST = '127.0.0.1'
PORT = 21567
PORT2 = 7777
BUFFER_SIZE = 1024

ADDR = (HOST, PORT)


def send_message(tcp_client_server, address):
    while True:
        msg = input('')
        data = str({"msg": msg, "target_address": ('127.0.0.1', 6666), "owner_address": address})
        tcp_client_server.send(data.encode('utf-8'))


def receive_message(tcp_client_server):
    # 接受消息
    while True:
        receive_data = tcp_client_server.recv(BUFFER_SIZE)  # 客户端接受消息
        print(receive_data.decode('utf-8'))


def main():
    # 创建对应客户端的套接字
    tcp_client_server = socket(AF_INET, SOCK_STREAM)  # 创建客户端套接字
    tcp_client_server.bind((HOST, PORT2))
    tcp_client_server.connect(ADDR)  # 尝试连接服务器
    address = tcp_client_server.getsockname()  # 返回当前套接字的地址
    print('当前套接字的地址:', address)

    thread = Thread(target=send_message, args=(tcp_client_server, address))
    thread.setDaemon(True)
    thread.start()

    recv_thread = Thread(target=receive_message, args=(tcp_client_server, ))
    recv_thread.setDaemon(True)
    recv_thread.start()

    thread.join()

    # 关闭套接字
    tcp_client_server.close()


if __name__ == '__main__':
    main()

           

TCP客户端2代码:

from socket import *
from threading import Thread


HOST = '127.0.0.1'
PORT = 21567
PORT2 = 6666
BUFFER_SIZE = 1024

ADDR = (HOST, PORT)


def send_message(tcp_client_server, address):
    while True:
        msg = input('')
        data = str({"msg": msg, "target_address": ('127.0.0.1', 7777), "owner_address": address})
        tcp_client_server.send(data.encode('utf-8'))


def receive_message(tcp_client_server):
    # 接受消息
    while True:
        receive_data = tcp_client_server.recv(BUFFER_SIZE)  # 客户端接受消息
        print(receive_data.decode('utf-8'))


def main():
    # 创建对应客户端的套接字
    tcp_client_server = socket(AF_INET, SOCK_STREAM)  # 创建客户端套接字
    tcp_client_server.bind((HOST, PORT2))
    tcp_client_server.connect(ADDR)  # 尝试连接服务器
    address = tcp_client_server.getsockname()  # 返回当前套接字的地址
    print('当前套接字的地址:', address)

    # 发送消息
    thread = Thread(target=send_message, args=(tcp_client_server, address))
    thread.setDaemon(True)
    thread.start()

    # 接收消息
    recv_thread = Thread(target=receive_message, args=(tcp_client_server,))
    recv_thread.setDaemon(True)
    recv_thread.start()

    recv_thread.join()

    # 关闭套接字
    tcp_client_server.close()


if __name__ == '__main__':
    main()
           

继续阅读