python网络通信器设计

总而言之、实现了简易的网络通信器,有群聊、单聊、控制、查看等的操作,完成了任务
不足:应用到了线程,在退出时并没有成功结束调度返回资源,而是将线程设为了守护线程,运行到了堵塞状态使程序不报错、后续学习了知识再来补充,也望大佬能评论赐教!

一、准备知识:

多套接字及多线程:**

在这里插入图片描述

在这里插入图片描述

进程与线程的区别

(可理解为一条马路-进程和马路上的多条车道-线程)

  1. 线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位;

  2. 一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线

  3. 进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段,数据集,堆等)及一些进程级的资源(如打开文件和信

号等),某进程内的线程在其他进程不可见;

  1. 调度和切换:线程上下文切换比进程上下文切换要快得多

    为何不使用多进程而是使用多线程?

    线程廉价,线程启动比较快,退出比较快,对系统资源的冲击也比较小。而且线程彼此分享了大部分核心对象(File Handle)的拥有权


二、通信器功能分析:

tcp socket(通信质量保障)

server:

群聊天(群聊窗口、接收消息后泛洪)

一对一(私聊窗口、接收消息后转发)

行为管理(只做了查看当前线程和关闭所有服务、未实现单个控制、也不难咯)

信息提示(进入或退出会输出提示)

client:

群聊天(发给服务器让服务器去泛洪)

一对一(发给发服务器让服务器代发)

退出控制


三、编写代码+功能验证

  • server信息提示:

在这里插入图片描述

在这里插入图片描述

  • 行为管理:

在这里插入图片描述

在这里插入图片描述

  • server群发:

在这里插入图片描述

  • server单发:

在这里插入图片描述

在这里插入图片描述

  • 代码
#欢迎大佬指正和修改
import socket
import threading
import logging
import datetime

FORMAT = "%(asctime)s %(threadName)s %(thread)d %(message)s"
logging.basicConfig(format=FORMAT, level=logging.INFO)

class socketS():
    #初始化,固定ip和port,绑定,监听
    def __init__(self):
        address = ('127.0.0.1', 9999)
        self.bufsize = 1024
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.bind(address)
        self.sock.listen()
        self.client_sock = {}   #空字典放所有的client sock对象,{key:ip, value:sock}
        self.thread_accept = threading.Thread(target=self.accept, name='accept', daemon=True)
        self.thread_accept.start()

    #建立连接、记录
    def accept(self):
        while True:
            sock, raddr = self.sock.accept()
            print("a new client connected!")
            logging.info(sock)
            logging.info(raddr)
            self.client_sock[raddr] = sock
            #线程传参、args=duple
            self.thread_recv = threading.Thread(target=self.recv, name='recv', daemon=True, args=(sock,))
            self.thread_recv.start()

    #接收和群发
    def recv(self, sock:socket.socket):
        while True:
            msg = sock.recv(self.bufsize).decode('gbk')
            # 单发
            single_msg = msg.split('%%%')
            if len(single_msg)>1:
                self.send(single_msg)
                # self.thread_send = threading.Thread(target=self.send, name='send', daemon=True, args=(single_msg,))
                # self.thread_send.start()
            #退出、从dict中删除
            elif msg == 'quit':
                print("a client have exited!")
                logging.info(sock.getpeername())
                self.client_sock.pop(sock.getpeername())
            else:
                msg = "{}\n {}: {}".format(
                    datetime.datetime.now().strftime("%Y/%m/%d-%H:%M:%S"),
                    sock.getpeername(),     #获取远端(ip, port)
                    msg).encode('gbk')
                for value in self.client_sock.values():
                    value.send(msg)

    #单发
    def send(self, single_msg):
        msg = single_msg[0]
        l_ip = single_msg[1]
        l_port = int(single_msg[2])
        r_ip = single_msg[3]
        r_port = single_msg[4]
        for key, value in self.client_sock.items():
            if l_ip == key[0] and l_port == key[1]:
                msg = "{}\n {}: {}".format(
                    datetime.datetime.now().strftime("%Y/%m/%d-%H:%M:%S"),
                    (r_ip, r_port),
                    msg).encode('gbk')
                value.send(msg)

    #关闭服务、貌似还有很大的问题
    def stop(self):
        print("server已关闭")
        self.thread_accept.join()
        self.thread_recv.join()
        # threading.Event.wait(1)      #阻塞线程直到内部变量为true。
        for value in self.client_sock.values():
            value.close()
        self.sock.close()

if __name__ == '__main__':
    ss = socketS()
    print("服务已启动,输入show查看当前线程,输入quit将关闭所有服务:")
    while True:
        cmd = input().strip()
        if cmd == 'quit':
            ss.stop()
        elif cmd == 'show':
            logging.info(threading.enumerate())
        else:
            print("a error cmd!")
  • client基本功能

选择连接、选择通信方式

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

import socket
import threading

class socketC():
    #初始化套接字
    def __int__(self, ip, port):
        address = (ip, port)
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.connect(address)
        print("connect successful!")
        self.thread_recv = threading.Thread(target=self.recv, name='recv', daemon=True)

    #一对一
    def chat(self):
        self.thread_recv.start()
        print("successful and input ip and port you need to chat")
        r_ip = input("ip:\n").strip()       #只需要输入一次
        r_port = input("port:\n").strip()
        l_address = self.sock.getsockname()     #return 自己的(ip, port)
        l_ip = str(l_address[0])
        l_port = str(l_address[1])
        while True:
            data = input().strip()
            if data == 'quit':
                print("end!!!")
                self.thread_recv.join()
                self.sock.close()
                return 0
            msg = (data + '%%%' + r_ip + '%%%' + r_port + '%%%' + l_ip + '%%%' + l_port).encode('gbk')
            self.sock.send(msg)

    #一对多
    def chat_group(self):
        self.thread_recv.start()
        print("chat_group start successful and you can chat now!")
        while True:
            msg = input().strip()
            if msg == 'quit':
                print("end!!!")
                self.thread_recv.join()
                self.sock.close()
                return 0
            msg = msg.encode('gbk')
            self.sock.send(msg)


    #公用接收
    def recv(self):
        bufsize = 1024
        while True:
            msg = self.sock.recv(bufsize).decode('gbk')
            print(msg)

if __name__ == '__main__':
    ip = input("please input server's ip:\n").strip()
    port = int(input("please input server's port:\n").strip())
    sc = socketC()
    sc.__int__(ip, port)
    while True:
        print("""****** please choose your operations: ************
                1、start a normal chat
                2、start a group chat""")
        print('*' * 50)
        options = int(input().strip())
        if options == 1:
            sc.chat()
        elif options == 2:
            sc.chat_group()
        else:
            print("a error cmd!")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值