首页 » 编程 » Python-7.并发编程 » 正文

socketserver模块

先来看个例子,最简单的服务端与客户端的聊天小程序。这个小程序只能实现一对一的聊天。

服务端:

# 服务端
import socket

address = ("127.0.0.1", 9090)
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(address)
server.listen(5)

while True:
    print("等待连接...")
    conn, addr = server.accept()
    print("addr: %s 已连接" % (addr,))
    while True:
        try:
            recv_data = conn.recv(1024).decode("utf-8")
            if not recv_data: break
            print("收到客户端信息:", recv_data)
            if recv_data == "exit":
                print("addr: %s 连接已断开" % (addr,))
                break
            while True:
                send_data = input("我:").strip()
                if not send_data: continue
                if send_data == "exit":
                    conn.send(send_data.encode("utf-8"))
                    raise ConnectionResetError
                conn.send(send_data.encode("utf-8"))
                break
        except ConnectionResetError:
            print("addr: %s 连接已断开" % (addr,))
            break
    conn.close()
server.close()

 

客户端:

# 客户端
import socket

address = ("127.0.0.1", 9090)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(address)

while True:
    inp = input(">>:").strip()
    if not inp: continue
    client.send(inp.encode("utf-8"))
    if inp == "exit": break
    recv_data = client.recv(1024).decode("utf-8")
    print("来自服务端消息:", recv_data)
    if recv_data == "exit":
        print("服务端主动断开,再见。")
        break
client.close()

运行如下:

服务端:

等待连接...
addr: ('127.0.0.1', 6982) 已连接
收到客户端信息: 你好
我:有啥事
收到客户端信息: 没事
我:exit
addr: ('127.0.0.1', 6982) 连接已断开
等待连接...

客户端:

>>:你好
来自服务端消息: 有啥事
>>:没事
来自服务端消息: exit
服务端主动断开,再见。

这个小程序只能实现一对一的聊天,并不能实现多个客户端同时聊天,要想实现和多个客户端同时聊天需要使用到多线程。

 

多线程版:

只需要稍微改动即可:

服务器端:

# 服务端
import socket
from threading import Thread

address = ("127.0.0.1", 9090)
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(address)
server.listen(5)


def tongxin(conn):
    while True:
        try:
            recv_data = conn.recv(1024).decode("utf-8")
            if not recv_data: break
            print("收到客户端 %s 的信息: %s " % (addr, recv_data))
            if recv_data == "exit":
                print("addr: %s 连接已断开" % (addr,))
                break
            while True:
                send_data = input("我:").strip()
                if not send_data: continue
                if send_data == "exit":
                    conn.send(send_data.encode("utf-8"))
                    raise ConnectionResetError
                conn.send(send_data.encode("utf-8"))
                break
        except ConnectionResetError:
            print("addr: %s 连接已断开" % (addr,))
            break
    conn.close()


while True:
    print("等待连接...")
    conn, addr = server.accept()
    print("addr: %s 已连接" % (addr,))
    t = Thread(target=tongxin, args=(conn,))
    t.start()
server.close()

客户端不变:

# 客户端
import socket

address = ("127.0.0.1", 9090)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(address)

while True:
    inp = input(">>:").strip()
    if not inp: continue
    client.send(inp.encode("utf-8"))
    if inp == "exit": break
    recv_data = client.recv(1024).decode("utf-8")
    print("来自服务端消息:", recv_data)
    if recv_data == "exit":
        print("服务端主动断开,再见。")
        break
client.close()

这样即可实现多个客户端都能够向服务器端发送消息,并可以得到回复。

 

 

从上面例子其实可以看出,我们每次在写网络编程相关的code的时候都需要必写的三句code:

address = ("127.0.0.1", 9090)
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(address)
server.listen(5)

其实有一个socketserver模块已经帮我们封装好了这些操作,并且开启多线程的操作也封装进去了,下面我们就使用socketserver模块来改造一下:

服务器端:

# 服务端
import socketserver  # 导入socketserver模块


class MyServer(socketserver.BaseRequestHandler):  # 必须继承BaseRequestHandler
    def handle(self):  # 固定写法,必须有一个handle方法,将要实现的功能模块放在里面
        while True:
            try:
                recv_data = self.request.recv(1024).decode("utf-8")  # 将原来的conn改为了 self.request
                if not recv_data: break
                print("收到客户端 %s 的信息: %s " % (self.client_address, recv_data))  # addr改为了self.client_address
                if recv_data == "exit":
                    print("addr: %s 连接已断开" % (self.client_address,))
                    break
                while True:
                    send_data = input("我:").strip()
                    if not send_data: continue
                    if send_data == "exit":
                        self.request.send(send_data.encode("utf-8"))
                        raise ConnectionResetError
                    self.request.send(send_data.encode("utf-8"))
                    break
            except ConnectionResetError:
                print("addr: %s 连接已断开" % (self.client_address,))
                break
        self.request.close()


server = socketserver.ThreadingTCPServer(("127.0.0.1", 9090), MyServer)  # 固定写法
server.serve_forever()  # 固定写法

 

客户端不变:

# 客户端
import socket

address = ("127.0.0.1", 9090)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(address)

while True:
    inp = input(">>:").strip()
    if not inp: continue
    client.send(inp.encode("utf-8"))
    if inp == "exit": break
    recv_data = client.recv(1024).decode("utf-8")
    print("来自服务端消息:", recv_data)
    if recv_data == "exit":
        print("服务端主动断开,再见。")
        break
client.close()

运行结果和多线程一样。

 

更多资料请参考:https://www.cnblogs.com/yuanchenqi/articles/9534816.html

 

 

发表评论

*