博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python网络编程
阅读量:3962 次
发布时间:2019-05-24

本文共 20234 字,大约阅读时间需要 67 分钟。

文章目录

socket

socket

客户端/服务器架构

C/S(Client/Server)架构
B/S(Browser/Server)架构

OSI(Open System Interconnect)七层模型

在这里插入图片描述

在这里插入图片描述
Socket
●socket (套接字)起源于Unix , socket即是一 种特殊的文件,一些socket函数就是对其
进行的操作(读/写IO、打开、关闭)
●它是TCP/IP网络环境下应用程序与底层通信驱动程序之间运行的开发接口,它可以将应
用程序与具体的TCP/IP隔离开来,使得应用程序不需要了解TCP/IP的具体细节, 就能够
实现数据传输。
●网络应用程序中, Socket通信是基于客户端/服务器结构。
在这里插入图片描述

服务端

"""服务器监听的方式1.监听IP+端口2.监听套接字 -> socket监听文件,Server端-> socket 发送接收数据,client端 -> socket发送接收数据Server -> socket <- Client本地服务服务端:1.创建socket2.绑定ip+port <- 客户端来连 接的时候3.监听客户端的连按4.接收客户端的请求-> 阻塞状态客户端与服务端进行交互=>接收数据/发送数据5.关闭socket客户端:1.创建socket2.诖接服务端=> ip+port客户端与服务端进行交互=>接收数据/发送数据3.关闭socket"""import socket#创建一个套接字server = socket.socket()#绑定监听ip和端口#0.0.0.0表示监听本机所有ip地址server.bind(("0.0.0.0",8888))#监听,设置可以有多个客户端连接进来server.listen(2)#接收客户端,如果进行accept时,程序进入阻塞状态#返回两个数据,一个是客户端连接,一个是ip和端口print("start.....")conn,addr = server.accept()print("有一个客户端连接进来了",conn,addr)#接收客户端数据#python3在网络上进行传输的格式都是bytes格式的accept_data = conn.recv(1024)print("接收的数据为:",str(accept_data,encoding="utf8"))#给客户端发送一个数据conn.sendall(bytes("thankyou!",encoding="utf8"))conn.close()print("end......")"""如果服务端建立连接之后,第一件事情是recv那么客户端第一件事情一定要send所以在编写cs服务时,注意数据发送和接收一定要一一对应"""

客户端

import socketclient = socket.socket()#参数是一个元组,连接器client.connect(("127.0.0.1",8888))send_data = input(">>>")client.sendall(bytes(send_data,encoding="utf8"))accept_data = client.recv(1024)print(str(accept_data,encoding="utf8"))client.close()

优化-客户端和服务端进行多次数据交互

#服务端import socket#创建一个套接字server = socket.socket()#绑定监听ip和端口#0.0.0.0表示监听本机所有ip地址server.bind(("0.0.0.0",8888))#监听,设置可以有多个客户端连接进来server.listen(2)#接收客户端,如果进行accept时,程序进入阻塞状态#返回两个数据,一个是客户端连接,一个是ip和端口print("start.....")conn,addr = server.accept()print("有一个客户端连接进来了",conn,addr)while True:    #接收客户端数据    #python3在网络上进行传输的格式都是bytes格式的    accept_data = conn.recv(1024)    print("接收的数据为:",str(accept_data,encoding="utf8"))    if not accept_data or accept_data == b"bye":        print("客户端要求断开")        break    #给客户端发送一个数据    conn.sendall(bytes("thankyou!",encoding="utf8"))conn.close()server.close()print("end......")#客户端import socketclient = socket.socket()#参数是一个元组,连接器client.connect(("127.0.0.1",8888))while True:    send_data = input(">>>")    if not send_data.strip():        continue    if send_data == "bye":        break    client.sendall(bytes(send_data,encoding="utf8"))    accept_data = client.recv(1024)    print(str(accept_data,encoding="utf8"))client.close()

优化-连接多个客户端

#服务端import socket#创建一个套接字server = socket.socket()#绑定监听ip和端口#0.0.0.0表示监听本机所有ip地址server.bind(("0.0.0.0",8888))#监听,设置可以有多个客户端连接进来server.listen(2)#接收客户端,如果进行accept时,程序进入阻塞状态#返回两个数据,一个是客户端连接,一个是ip和端口print("start.....")while True:    conn,addr = server.accept()    print("有一个客户端连接进来了",conn,addr)    while True:        #接收客户端数据        #python3在网络上进行传输的格式都是bytes格式的        accept_data = conn.recv(1024)        print("接收的数据为:",str(accept_data,encoding="utf8"))        if not accept_data or accept_data == b"bye":            print("客户端要求断开")            break        #给客户端发送一个数据        conn.sendall(bytes("thankyou!",encoding="utf8"))    conn.close()server.close()print("end......")#客户端import socketclient = socket.socket()#参数是一个元组,连接器client.connect(("127.0.0.1",8888))while True:    send_data = input(">>>")    if not send_data.strip():        continue    if send_data == "bye":        break    client.sendall(bytes(send_data,encoding="utf8"))    accept_data = client.recv(1024)    print(str(accept_data,encoding="utf8"))client.close()

socket-tcp编程

●socket ( )

s = socket.socket(socket_ family,socket type,protocal=0)
socket
family:
socket.AF
INET IPv4 (默认)
eP)
sockct.AF_ INET6 IPv6
socket.AF_ UNIX 只能够用于单一-的Unix系统进程间通信
socket_ type:
socket.SOCK_ STREAM 流式socket , tor TCP (默认)
socket.SOCK_ DGRAM 数据报式socket,forUDP
socket.SOCK_ RAW原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_ RAW可以;其次,SOCK_ RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_ _HDRINCL套 接字选项由用户构造IP头。
config.py

addr = ("0.0.0.0",8888)

server.py

import socketimport configwith socket.socket(socket.AF_INET,socket.SOCK_DGRAM) as server:    server.bind(config.addr)    print("start")    while True:        data = server.recv(1024)        print(data)

client.py

import socketimport configwith socket.socket(socket.AF_INET,socket.SOCK_DGRAM) as client:    while True:        data =bytes(input(">>>"),encoding="utf8")        if data == "exit":            break        client.sendto(data,config.addr)

TCP与UDP的区别

TCP =>面向连按,有状态的。确保数据完螯性
UDP =>面向无洼按。有可能会丢包
TCP服务=>需要先启动服务端,再劣客户端连接
ConnectionRefusedError: [Errno 111] Connection refused
ConnectionRefusedError: [WinError 10061]由于日标计算札积极拒绝,无法连接。
UDP => 可以直接启动客户端。不报错,但是肯定也是无法发送数据给服务端的。
可能的原囚:
1.网络连通性=> 192.168.0.110 => ping
2.端口连通性=> telnet
|通」, 马上会断开连接=>服务内部白名单
3.端不通?
a. selinux => Disable
b. firewalld/iptables
c.服务是否启动
d.监听地端几是不是正确

粘包现象

●只有基于tcp的socket

●粘包:发送方发送两个字符串”hello" +”world" ,接收方却一次性接收到
了”helloworld"
●为什么会产生粘包?
应用程序所看到的数据是一个流( stream) , 一条消息有多少字节对应用程序是不可见
的,因此TCP协议是面向流的协议,这也是容易出现粘包问题的原因。
根本原因:两端互相不知道对方发送数据的长度

server.py

import socketimport configwith socket .socket() as server:    server.bind(config . addr)    server.listen(2)    print("start......")    conn, addr = server. accept( )    print("有一个客户端连接进米了",conn, addr)    accept_data = conn. recv(1024)    print("接收到的数据为:",str(accept_data, encoding="utf-8"))    accept_data = conn . recv(1024)    print("接收到的数据为:", str(accept_data, encoding="utf-8"))    print("end......")

client.py

import socketimport configwith socket.socket() as client:    client.connect(config. addr)    client.sendall(bytes("hello",encoding="utf-8"))    client.sendall(bytes("world",encoding="utf-8"))

解决

"""TCP粘包的产生TCP是数据是Stream,一条消息有多少个字节,程序不可知的发送的时候,两条消息间隔很近接收的时候,不知道消息的长度,于是就两条消息当作一条消息按收了。sendall + input + sendall=>不粘包sendall + print + sendll =〉粘包如何解决?1.sendall + time.sleep + sendLL =>不粘包2.send + recv + send => """#方式一import socketimport configwith socket.socket() as client:    client.connect(config. addr)    a = input(">>>")    client.sendall(bytes(a,encoding="utf-8"))    b = input(">>>")    client.sendall(bytes(b,encoding="utf-8"))#方式二#client.pyimport socketimport configwith socket.socket() as client:    client.connect(config. addr)    client.sendall(bytes("hello",encoding="utf-8"))    client.recv(1024)    client.sendall(bytes("world",encoding="utf-8"))#server.pyimport socketimport configwith socket .socket() as server:    server.bind(config.addr)    server.listen(2)    print("start......")    conn, addr = server.accept()    print("有一个客户端连接进米了",conn, addr)    accept_data = conn.recv(1024)    print("接收到的数据为:",str(accept_data, encoding="utf-8"))    conn.sendall(b"ok")    accept_data = conn.recv(1024)    print("接收到的数据为:", str(accept_data, encoding="utf-8"))    print("end......")
ftp服务器
"""1.启动ftp服务器2.连接ftp服务器3.client => filename_path /tmp/a.jpg    服务端读本地文件内容,发送给客户端    客户端保存服务器发送过来的内容4.在本地文件能打开能为一个客户端提供多次服务即可""""""服务端"""import osimport socketimport configwith socket.socket() as server:    server.bind(config.ftp_addr)    server.listen(2)    while True:        conn , addr = server.accept()        print("客户端连接过来了~",addr,conn)        #为客户端提供服务        while True:            file_path = conn.recv(1024)            if not file_path:break            if not os.path.exists(file_path):                conn.sendall("文件目录不存在".encode("utf8"))                continue            print("开始传输",file_path)            with open(file_path,"rb") as f:                file_data = f.read()                conn.sendall(str(len(file_data)).encode("utf8"))                conn.recv(1024)                conn.sendall(file_data)"""ftp客户端"""import osimport socketimport configwith socket.socket() as client:    client.connect(config.ftp_addr)    #用户可以多次下载文件    while True:        data = input("请输入您要下载的文件路径---exit退出")        if not data.strip():continue        if data == "exit": break        filename = os.path.split(data)[-1]        #将要下载的文件路径发送到服务器        client.send(bytes(data,encoding="utf-8"))        #接收服务器发送过来的数据(思考:如果接收的文件数据特别大怎么办?服务端发送数据时,告诉我们文件大小是多少)        file_length = client.recv(1024)        client.sendall(b"ok")        file_data = b""        while True:            file_data += client.recv(1024)            if len(file_data) >= int(file_length):break        with open(filename,"wb") as f:            f.write(file_data)
ftp服务器-多客户端
"""服务端"""import osimport socketimport threadingimport configdef worker(conn,addr):    print("客户端连接过来了~",addr,conn)    #为客户端提供服务    while True:        file_path = conn.recv(1024)        if not file_path:break        if not os.path.exists(file_path):            conn.sendall("文件目录不存在".encode("utf8"))            continue        print("开始传输",file_path)        with open(file_path,"rb") as f:            file_data = f.read()            conn.sendall(str(len(file_data)).encode("utf8"))            conn.recv(1024)            conn.sendall(file_data)with socket.socket() as server:    server.bind(config.ftp_addr)    server.listen(2)    while True:        conn , addr = server.accept()        t = threading.Thread(target=worker,args=(conn,addr))        t.start()"""ftp客户端"""import osimport socketimport configwith socket.socket() as client:    client.connect(config.ftp_addr)    #用户可以多次下载文件    while True:        data = input("请输入您要下载的文件路径---exit退出")        if not data.strip():continue        if data == "exit": break        filename = os.path.split(data)[-1]        #将要下载的文件路径发送到服务器        client.send(bytes(data,encoding="utf-8"))        #接收服务器发送过来的数据(思考:如果接收的文件数据特别大怎么办?服务端发送数据时,告诉我们文件大小是多少)        file_length = client.recv(1024)        client.sendall(b"ok")        file_data = b""        while True:            file_data += client.recv(1024)            if len(file_data) >= int(file_length):break        with open(filename,"wb") as f:            f.write(file_data)

socket-udp编程

select

linux io模型

阻塞io

买一件事情的时候,等待回复/资源,如果没有得到回复资源,只会等待,其他任何事情都不做
买票=>老王去火车站买票=>排队->一直等->轮到他
烧水=>烧一壶谁=>等水开(在水开之前,什么都不做)

非阻塞io

做一件事的时候,等待回复,先去干一件其他的事情,等一下再来问情况
买票 => 老王去火车站买票->排队看一下->隔N个小时再来看一下
烧水=>烧一壶谁=>等5分钟去看一眼是不是开了

i0多路复用

nginx的并发,如果一个请求i/o,开启一个进程/线程处理这个请求
如果一下就进来2万个请求,是否直接开启2w个线程/进程处理请求
i/o多路复用模型=> 一个线程通过记录i/o状态来同时管理多个i/o,提升服务器的吞吐能力
一个线程管理1024个连接i/o,2万个20个线程
select,poll,epoll

信号驱动io

买一件事情的时候,等待回复/资源,如果没有得到回复资源,先去干别的,第有资源,会通知
买票->留个信息给管理员->有票->打电话通知->去火车站交钱买票

异步io

买一件事情的时候,等待回复/资源,如果没有得到回复资源,先去干别的,第有资源,自动调用并完成接下来的任务
买票->留个信息给管理员->有票->打电话通知->把票寄给你

io多路复用

Select和poll的区别(select有数量的限制1024,poll没有数量的限制)

select-> 1024个fd ->对所有的描述符进行遍历->找出就绪转态的fd
换尿布=>select=>1024=>定期去检查每个baby是否尿片是不是湿了=>找到所有尿布湿了的小孩
找人=>select=>问每一个人

epoll->等通知型

换尿布=>select=>1024=>高级尿布,感应器=>如果湿了,响…=>去给他换

select/poll:

1、当有io就绪,select会遍历所有的fd,来找到就绪fd
2、每次调用select(), 都会把所有的fd_ set从用户态拷贝到内核态
3、select所监控的fd_ set有限制,一般来说最多 只能监听1024个。
4、poll跟select实现类似,只是poll 没有fd监控数量限制

epoll:

1、没有并发连接的限制
2、效率提升不是采用轮询方式,而是回调(有结果通种)
3、fd在整个过程中只拷贝-次

select模块

Python中的select模块专注于I/O多路复用,提供了select、poll、

epoll三个方法
poll epollI在linux中可用 , windows仅支持select。

进程指定内核监听哪些文件描述符(最多监听1024个fd)的哪些事件,当没有文件描述符事件发生

时,进程被阻塞;
当一个或者多个文件描述符事件发生时1进程被唤醒。
文件描述符:
对于Linux而言,所有对设备或文件的操作都是通过文件描述符进行的。

select方法用来监视文件描述符(当文件描述符条件不满足时, select会阻塞) ,当某个文件描述符状态改变

后,会返回三个列表。
fd_ r_ list, fd_ w_ list, fd_ e_ list = select.select(rlist, wlist, xlist, [timeout])
参数:可接受四个参数(前三个必须)
rlist: wait until ready for reading (所有的输入的data,就是指外部发过来的数据)
当序列中的fd满足“可读”条件时,则获取发生变化的fd并添加到fd r_ list中
wlist: wait until ready for writing ( 监控和接收所有要发出去的data )
●当参数2序列中含有fd时,则将该序列中所有的fd添加到fd_ w_ list中
xlist: wait for an “exceptional condition” ( 监控错误信息)
●当参数3序列中的fd发生错误时,则将该发生错误的fd添加到fd_ e list中
三创教育
timeout:超时时间。当超时时间为空 ,则select会-直阻塞,直到监听的句柄发生变化

小案例

"""select-server"""import socketimport selectimport configwith socket.socket() as server:    server.bind(config.addr)    server.listen(5)    rlist = [server]    while True:        #当我们执行到这来,程序就会阻塞,等待rlist就绪        rl , _ , _ = select.select(rlist,[],[])        #遍历所有操作fd        for fd in rl:            #如果fd是server=>有新的连接过来            if fd == server:                conn,addr = server.accept()                print("有客户端连接过来了")                #将客户端加入到监听列表                rlist.append(conn)                #接收客户端发送的数据,并直接返回                msg = conn.recv(1024)                conn.sendall(msg)            else:                #已经建立连接的客户端                msg = fd.recv(1024)                if not msg:                    rlist.remove(fd)                    fd.close()                else:                    fd.sendall(msg)"""select-client"""import socketimport configwith socket.socket() as client:    client.connect(config.addr)    while True:        data = input("请输入要发送的数据(exit):")        if not data.strip():continue        elif data.strip() == "exit":break        client.sendall(bytes(data,encoding="utf8"))        print("recv:",client.recv(1024))

解决bug

"""select-server"""import socketimport selectimport configimport threadingdef newclient(conn):    # 接收客户端发送的数据,并直接返回    msg = conn.recv(1024)    conn.sendall(msg)def oldclient(fd):    # 已经建立连接的客户端    msg = fd.recv(1024)    if not msg:        rlist.remove(fd)        fd.close()    else:        fd.sendall(msg)with socket.socket() as server:    server.bind(config.addr)    server.listen(5)    rlist = [server]    while True:        #当我们执行到这来,程序就会阻塞,等待rlist就绪        rl , _ , _ = select.select(rlist,[],[])        #遍历所有操作fd        for fd in rl:            #如果fd是server=>有新的连接过来            if fd == server:                conn,addr = server.accept()                print("有客户端连接过来了")                #将客户端加入到监听列表                rlist.append(conn)                t1 = threading.Thread(target=newclient,args=(conn,))                t1.start()            else:                t2 = threading.Thread(target=oldclient,args=(fd,))                t2.start()

select与poll

1、select采用轮询的方式遍历所有fd ,监控对应事件是否发生
2、select需要在用户空间与内核空间频繁拷贝fd
3、 select最大仅仅支持1024个文件描述符
4、poll与select相差不大, poll无文件描述符监听限制。

epoll

1、注册新事件时,就将fd拷贝进内核,每个fd在整个过程中只会拷贝一次。
2、为每个fd指定一个回调函数 ,当设备就绪,调用这个回调函数。
3、epoll对文件描述符没有额外限制

epoll

select.epoll()创建epoll对象

epoll.close()关闭epoll对象的文件描述符
epoll.closed检测epol对象是否关闭
epoll.fileno()返回epoll对象的文件描述符
epoll.register(fd[, eventmask])向epoll对象中注册fd和对应的事件
epoll.unregister(fd)取消注册
事件:
EPOLLIN Available for read可读状态符为1
EPOLLOUT Available for write可写状态符为4
EPOLLERR Error condition happened on the assoc. fd发生错误状态符为8

"""epoll-server"""import socketimport selectimport configwith socket.socket() as server:    server.bind(config.addr)    server.listen(5)    #创建一个epoll对象    epoll_obj = select.epoll()    # 将server注册带epoll_obj,监听读事件    epoll_obj.register(server,select.EPOLLIN)    # 存放所有的客户端信息    connections = {
} while True: # events 就绪的对象 events = epoll_obj.poll() for fd,event in events: print(fd,event) #区分新连接和已经建立的连接 #新连接 if fd == server.fileno(): conn,addr = server.accept() connections[conn.fileno()] = conn epoll_obj.register(conn,select.EPOLLIN) msg = conn.recv(1024) conn.sendall(msg) #已经建立的连接 else: conn = connections[fd] msg = conn.recv(1024) # 客户端断开连接,从epoll中取消注册,并断开连接 if not msg: epoll_obj.unregister(fd) conn.close() del connections[fd] else: conn.sendall(msg)"""epoll-client"""import socketimport configwith socket.socket() as client: client.connect(config.addr) while True: data = input("请输入要发送的数据(exit):") if not data.strip():continue elif data.strip() == "exit":break client.sendall(bytes(data,encoding="utf8")) print("recv:",client.recv(1024))

socketserver

SocketServer内部使用I0多路复用以及“多线程” 和“多进程”, 从而实现并发处理多个客户端请求的Socket服务端。

即:每个客户端请求连接到服务器时,Socket服务端都会在服务器是创建一个“线程”或者"进程”专门负责处理当前客户端的所有请求。
socketserver将socket模块和select模块进行了封装,简化网络服务器版的开发。
socketserver最主要的作用:就是实现一个并发处理。

SocketServer类

四个比较主要的类,其中常用的是TCPServer和UDPServer

1、 TCPServer
2、UDPServer
3、UnixStreamServer,类似于TCPServer提供面向数据流的套接字连接,但是旨在UNIX平台上可用;
4、UnixDatagramServer,类似于UDPServer提供面向数据报的套接字连接,但是旨在UNIX平台上可用;
两种支持异步处理的类:
1、ForkingMixIn ,为每一个客户端请求派生一个新的进程去专门处理;
2、ThreadingMixIn ,为每一个客户端请求派生一 个新的线程去专门处理;
继承自这两个类型的服务端在处理新的客户端连接时不会阻塞,而是创建新的进/线程专门处理安户端的请求.

创建SocketServer

1、创建一一个请求处理类)继承BaseRequestHandlerclass类并且重写父类的handle()方

法,该方法将处理传入的请求。
2、必须实例化-个上面类型中的一个类(如TCPServer )传递服务器的地址和你上面创建
的请求处理类给这个TCPServer。
3、调用handle_ request()或者serve_ forever()方法来处理一个或多个请求
4、调用server close()关闭socket

# socketserver-serverimport socketserverimport configclass MyRequestHandler(socketserver.BaseRequestHandler):    """'这个类的功能-> 每一个请求过来, 应该如何处理"""    def handle(self):        """核心部分:处理接收的数据"""        # self.request =>类定义的方法=>表示客户端的请求        while True:            data = self.request.recv(1024)            print(data)            if not data: break            # 发送数据回去            self.request.sendall(data)if __name__ == "__main__":    # 一次只能处理一个客户端的请求! !因为这里并没有使用多进程或多线程    # server = socketserver . TCPServer(config. addr, MyRequestHandLer)    # 一次处理qqr个客户端的请求! !因为这里并没有使用多进程或多线程    # server = socketserver.TCPServer(config.addr,MyRewuestHandler)    server = socketserver.ThreadingTCPServer(config.addr,MyRequestHandler)    print("start...")    server.serve_forever()    server.server_close()# socketserver-clientimport socketimport configwith socket.socket() as client:    client.connect(config.addr)    while True:        data = input(">>>")        if not data:continue        if data == "exit":break        client.sendall(bytes(data,encoding="utf8"))        recv = client.recv(1024)        print(str(recv,encoding="utf8"))    client.close()

案例-聊天

"""服务器=>启动=>1.启动服务并监听2.服务端接收到用户连接3.接收用户数据=> @setnome =》返回欢迎您, XXX=》clientf 与client2通信=>保存起来=> {username: username-socket} =>实例属性/类局烟=》@username =>发送消息给username => 难点?=》username => username-socket =》socket.send(消息内容)=> 如果username找不到对应的socket, 给自己回一个消息-> (当前用户不存在)=如果断开连接,那么从字典中删除"""import socketserverimport configclass MyRequestHandler(socketserver.BaseRequestHandler):    """这个类的功能 -> 每一个请求过来,应该如何处理"""    socket_dict = dict()    def handle(self):        """核心部分:处理接收的数据"""        print("一个新客户端连接来啦!")        while True:            print("当前所有的用户有", self.socket_dict)            # self.request => 类定义的方法 => 表示客户端的请求            data = str(self.request.recv(1024), encoding="utf-8")            if not data: break            print("接收到的数据是:", data)            if data.startswith("@setname"):                print("设置用户名") # "@setname lxl abc"                username = ''.join(data.split()[1:])                self.request.sendall(bytes(f"欢迎你!{username}!", encoding="utf-8"))                # 设置当前用户名 => 动态为请求添加了一个socket                self.username = username                self.add_client(username, self.request)            elif data.startswith("@"):                # "@lihu xxxx xxx2"                to = data.split()[0][1:]                message = " ".join(data.split()[1:])                if to in self.socket_dict:                    # {"ryc": socket, "lxl": socket}                    print(f"给{to}发消息")                    self.socket_dict[to].sendall(bytes(message, encoding="utf-8"))                    self.request.sendall(bytes("", encoding="utf-8"))                else:                    self.request.sendall(bytes(f"您聊天的对象({to})不存在", encoding="utf-8"))            else:                self.request.sendall(bytes(f"数据有误!{data}", encoding="utf-8"))    @classmethod    def add_client(cls, username, client):        cls.socket_dict[username] = client        print("当前所有的用户有",cls.socket_dict)    @classmethod    def remove_client(cls, username):        cls.socket_dict.pop(username)    def finish(self):        """一个客户端断开"""        if hasattr(self, "username"):            self.remove_client(self.username)            print(f"{self.username}退出了~")if __name__ == "__main__":    # 一次只能处理一个客户端的请求!!因为这里并没有使用多进程或多线程    # server = socketserver.TCPServer(config.addr, MyRequestHandler)    # 同时处理多个客户端的请求!    server = socketserver.ThreadingTCPServer(config.addr, MyRequestHandler)    print("start....")    server.serve_forever()    server.server_close()"""客户端=>启动1.连接服务器2.输入你的名字发送给服务端 => @setname x0x3. 与谁聊天(呢称-》Lihu) => @Lihu infomation4.如果输入的数据是=> @exit =>表示要断开连接"""import socketimport configwith socket.socket() as client:    client.connect(config.addr)    while True:        data = input(">>>")        if not data: continue        if data == "@exit": break        client.sendall(bytes(data, encoding="utf-8"))        recv = client.recv(1024)

转载地址:http://yhezi.baihongyu.com/

你可能感兴趣的文章
inet_ntoa()
查看>>
POSIX消息队列mq_open问题
查看>>
两个数组a[N],b[N],其中A[N]的各个元素值已知,现给b[i]赋值,b[i] = a[0]*a[1]*a[2]…*a[N-1]/a[i];
查看>>
用户态切换到内核态的3种方式
查看>>
笔试常见的智力题(附答案)
查看>>
内核库函数
查看>>
Linux 系统内核空间与用户空间通信的实现与分析
查看>>
如何写好应用型学术论文
查看>>
如何查看进程的各种限制
查看>>
64位int类型用printf输出问题
查看>>
网络后台开发面试题目
查看>>
Linux 共享内存限制的查看与设置
查看>>
进程的状态转换
查看>>
如何查看进程的信息(线程数)
查看>>
Linux中的chage命令
查看>>
linux-详细解析密码文件passwd与shadow
查看>>
su- 与su的区别
查看>>
linux下发邮件mail
查看>>
echo如何手动输出换行
查看>>
身份证的正确使用方法——非常重要的知识
查看>>