zoukankan      html  css  js  c++  java
  • 采用tcp协议和UDP协议实现简单的聊天功能

    Date: 2019-06-19

    Author: Sun

    一. Python3输出带颜色字体

    实现过程:

    ​ 终端的字符颜色是用转义序列控制的,是文本模式下的系统显示功能,和具体的语言无关。

    ​ 转义序列是以ESC开头,即用\033来完成(ESC的ASCII码用十进制表示是27,用八进制表示就是033)。

    书写格式:

    ​ 开头部分**:\033[显示方式;前景色;背景色m + **结尾部分:\033[0m

    ​ 注意:开头部分的三个参数:显示方式,前景色,背景色是可选参数,可以只写其中的某一个;另外由于表示三个参数不同含义的数值都是唯一的没有重复的,所以三个参数的书写先后顺序没有固定要求,系统都能识别;但是,建议按照默认的格式规范书写。

    ​ 对于结尾部分,其实也可以省略,但是为了书写规范,建议\033[***开头,\033[0m结尾。

    数值表示的参数含义:

    显示方式: 0(默认\)、1(高亮)、22(非粗体)、4(下划线)、24(非下划线)、 5(闪烁)、25(非闪烁)、7(反显)、27(非反显)
    前景色: 30(黑色)、31(红色)、32(绿色)、 33(黄色)、34(蓝色)、35(洋 红)、36(青色)、37(白色)
    背景色: 40(黑色)、41(红色)、42(绿色)、 43(黄色)、44(蓝色)、45(洋 红)、46(青色)、47(白色)

    采用前景色配色方案:

    print("前景色:")
    print("\033[0;30;40m\t前景色-黑色\033[0m")
    print("\033[0;31;40m\t前景色-红色\033[0m")
    print("\033[0;32;40m\t前景色-绿色\033[0m")
    print("\033[0;33;40m\t前景色-黄色\033[0m")
    print("\033[0;34;40m\t前景色-蓝色\033[0m")
    print("\033[0;35;40m\t前景色-洋 红\033[0m")
    

    采用背景色配色方案:

    print("背景色::")
    print("\033[0;37;40m\t背景色-黑色\033[0m")
    print("\033[0;37;41m\t背景色-红色\033[0m")
    print("\033[0;37;42m\t背景色-绿色\033[0m")
    print("\033[0;37;43m\t背景色-黄色\033[0m")
    print("\033[0;37;44m\t背景色-蓝色\033[0m")
    print("\033[0;37;45m\t背景色-洋 红\033[0m")
    print("\033[0;37;46m\t背景色-青色\033[0m")
    print("\033[0;37;47m\t背景色-白色\033[0m")
    

    print打印文字和带颜色的局部情况:

    print('This is a \033[1;35m test \033[0m!')
    print('This is a \033[1;32;43m test \033[0m!')
    print('\033[1;33;44mThis is a test !\033[0m')
    

    输出结果:

    二. TCP协议实现简单聊天功能

    ​ 聊天室往往是最基本的网络编程的学习案例, 本节采用TCP协议实现简单聊天功能

    TCP协议实现简单聊天功能

    服务器端程序

    # -*- coding: utf-8 -*-
    __author__ = 'sun'
    __date__ = '2019/6/19 15:17'
    
    from socket import *
    
    # 创建socket
    tcpSerSocket = socket(AF_INET, SOCK_STREAM)
    
    # 绑定本地信息
    address = ('', 8080)
    tcpSerSocket.bind(address)
    
    #  使⽤socket创建的套接字默认的属性是主动的,使⽤listen将其变为被动的,这样就可以接
    tcpSerSocket.listen(5)
    
    while True:
        # 如果有新的客户端来链接服务器,那么就产⽣⼀个信⼼的套接字专⻔为这个客户端服务器
        # #    newSocket⽤来为这个客户端服务
        # #    tcpSerSocket就可以省下来专⻔等待其他新客户端的链接
        print("\033[0;35;40m\twaiting for client connect...\033[0m")
        newSocket, clientSocket = tcpSerSocket.accept()
        while True:
            # 接收对⽅发送过来的数据,最⼤接收1024个字节
            recvData = newSocket.recv(1024)    #recv接受到的是bytes   
            if len(recvData) > 0:
                rev_data = recvData.decode('utf8')     #bytes ---》str   .decode('utf8')
                #背景色-绿色
                print(f"[接受客户端数据]<---- \033[0;31;40m\t{rev_data}\033[0m")
            else:
                print("close and break.")
                break
            # 发送数据到客户端
            #背景色 - 黄色
            sendData = input("[服务器端发送数据]----> \033[0;32;40m\t\033[0m:")
            newSocket.send(sendData.encode('utf8'))
        newSocket.close()
    
    tcpSerSocket.close()
    

    客户端程序:

    # -*- coding: utf-8 -*-
    __author__ = 'sun'
    __date__ = '2019/6/19 15:18'
    
    from socket import *
    '''
        客户端
    '''
    # 创建socket
    tcpClientSocket = socket(AF_INET, SOCK_STREAM)
    
    # 连接服务器
    serAddr = ("127.0.0.1", 8080)
    tcpClientSocket.connect(serAddr)
    
    while True:
        # 提示用户输入输入
        sendData = input("请输入内容:")
        if len(sendData) > 0:
            send_data = sendData.encode('utf8')
            tcpClientSocket.send(send_data)
            print(f"[客户端发送数据]----> \033[0;31;40m\t{send_data}\033[0m")
        else:
            break
    
        # 接收对方发送的消息
        recv = tcpClientSocket.recv(1024)
        recv_data = recv.decode('utf8')
        #print("127.0.0.1:\n" + recv.decode('utf8'))
        print(f"[客户端接受数据]<---- \033[0;32;40m\t{recv_data}\033[0m")
    # 关闭套接字
    tcpClientSocket.close()
    

    至此,基于TCP协议的简单功能的聊天功能已经完成。

    三. UDP协议实现简单聊天室

    服务器和客户端使用UDP编程,客户端两个线程一个负责接收,一个负责发送。

    服务器:接收消息并保存地址,如果触发‘EXIT’关键字则从地址表中移除该地址。

    服务器端代码:

    采用多线程方式实现

    udp_server.py

    # -*- coding: utf-8 -*-
    __author__ = 'sun'
    __date__ = '2019/6/19 17:20'
    
    import socket
    import threading
    def main():
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        addr = ('127.0.0.1', 9998)
        s.bind(addr)
        print('UDP Server on %s:%s...', addr[0], addr[1])
    
        user = {}  # {addr:name}
        while True:
            try:
                data, addr = s.recvfrom(1024)
                if not addr in user:
                    for address in user:
                        s.sendto(data + ' 进入聊天室...'.encode(), address)
                    user[addr] = data.decode('utf-8')
                    continue
    
                if 'EXIT' in data.decode('utf-8'):
                    name = user[addr]
                    user.pop(addr)
                    for address in user:
                        s.sendto((name + ' 离开了聊天室...').encode(), address)
                else:
                    print('"%s" from %s:%s' %
                          (data.decode('utf-8'), addr[0], addr[1]))
                    for address in user:
                        if address != addr:
                            s.sendto(data, address)
    
            except ConnectionResetError:
                print('Someone left unexcept.')
    
    
    if __name__ == '__main__':
        main()
    

    客户端代码 udp_client.py

    两个线程,并设置接收线程为守护线程

    # -*- coding: utf-8 -*-
    __author__ = 'sun'
    __date__ = '2019/6/19 17:38'
    import socket
    import threading
    def recv(sock, addr):
        '''
        一个UDP连接在接收消息前必须要让系统知道所占端口
        也就是需要send一次,否则win下会报错
        “   data=sock.recv(1024)
            OSError: [WinError 10022] 提供了一个无效的参数。   ”
        '''
        sock.sendto(name.encode('utf-8'), addr)
        while True:
            data = sock.recv(1024)
            print(data.decode('utf-8'))
    
    def send(sock, addr):
        while True:
            string = input()
            message = name + ' : ' + string
            data = message.encode('utf-8')
            sock.sendto(data, addr)
            if string == 'EXIT':
                break
    
    def main():
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        server = ('127.0.0.1', 9998)
    
        tr = threading.Thread(target=recv, args=(s, server), daemon=True)
        ts = threading.Thread(target=send, args=(s, server))
        tr.start()
        ts.start()
        ts.join()
        s.close()
    
    if __name__ == '__main__':
        print("-----欢迎来到聊天室,退出聊天室请输入'EXIT'-----")
        name = input('请输入你的名称:')
        print('-----------------%s------------------' % name)
        main()
    

    启动服务器端代码:python udp_server.py

    分别启动两个终端启动客户端代码:python udp_client.py

  • 相关阅读:
    Python 入门 之 print带颜色输出
    memcache缓存
    PDO
    面向对象(二)
    面向对象(一)
    文件上传
    简单的权限管理
    当前时间与时期联动
    淡入淡出、滑动、及遍历
    留言板相关功能
  • 原文地址:https://www.cnblogs.com/sunBinary/p/11055577.html
Copyright © 2011-2022 走看看