多線程實現socket通信伺服器端代碼 import socket import threading class MyServer(object): def __init__(self): # 初始化socket self.server = socket.socket(socket.AF_INET, ...
多線程實現socket通信伺服器端代碼
import socket
import threading
class MyServer(object):
def __init__(self):
# 初始化socket
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 設置伺服器IP地址
host = '192.168.152.1'
# 設置伺服器埠號
port = 4321
# 綁定IP地址和埠
self.server.bind((host, port))
# 設置最大監聽數
self.server.listen(5)
# 設置一個字典,用來保存每一個客戶端的連接和身份信息
self.socket_mapping = {}
# 設置接收的最大位元組數
self.maxSize = 1024
def run(self):
while True:
socket, addr = self.server.accept()
# 發送信息,提示客戶端已成功連接
socket.send('success!'.encode('utf-8'))
# 將客戶端socket等信息存入字典
self.socket_mapping[socket] = addr
# 創建線程,負責獲取鍵盤輸入併發送給客戶端
threading.Thread(target=self.send_to_client, args=(socket,)).start()
# 創建線程,負責接收客戶端信息並轉發給其他客戶端
threading.Thread(target=self.recv_from_client, args=(socket,)).start()
def send_to_client(self, socket):
"""
獲取鍵盤輸入併發送給客戶端
:param socket:
:return:
"""
while True:
info = input()
if info == "quit":
socket.close()
for socket in self.socket_mapping.keys():
socket.send(info.encode("utf-8"))
def recv_from_client(self, socket):
"""
接收客戶端信息並轉發給其他客戶端
:param socket:
:return:
"""
while True:
recv_info = socket.recv(self.maxSize).decode('utf-8')
print('client{} say: '.format(self.socket_mapping[socket]), recv_info)
for i_socket in self.socket_mapping.keys():
if i_socket != socket:
i_socket.send(recv_info.encode("utf-8"))
my_server = MyServer()
my_server.run()
多進程實現socket通信伺服器端代碼
存在的問題:在與客戶端連通後,需要伺服器先發送兩條消息,之後才能正常通信。
import os
import socket
import sys
from multiprocessing import Process, Manager
class MyServer(object):
def __init__(self):
# 初始化socket
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 設置伺服器IP地址
host = '192.168.152.1'
# 設置伺服器埠號
port = 4321
# 綁定IP地址和埠
self.server.bind((host, port))
# 設置最大監聽數
self.server.listen(5)
# 設置一個字典,用來保存每一個客戶端的連接和身份信息
self.socket_mapping = Manager().dict()
# 設置接收的最大位元組數
self.maxSize = 1024
# 進程鎖
self.share_lock = Manager().Lock()
def run(self):
fn = sys.stdin.fileno()
while True:
socket, addr = self.server.accept()
# 發送信息,提示客戶端已成功連接
socket.send('success!'.encode('utf-8'))
# 將客戶端socket等信息存入字典
self.modify_mapping(self.socket_mapping, addr, socket, self.share_lock)
# 創建進程,負責獲取鍵盤輸入併發送給客戶端
Process(target=self.send_to_client, args=(addr, fn)).start()
# 創建進程,負責接收客戶端信息並轉發給其他客戶端
Process(target=self.recv_from_client, args=(addr,)).start()
def send_to_client(self, addr, fn):
"""
獲取鍵盤輸入併發送給客戶端
:param addr:
:return:
"""
sys.stdin = os.fdopen(fn)
while True:
info = sys.stdin.readline()
if info == "quit":
self.socket_mapping[addr].close()
for socket in self.socket_mapping.values():
socket.send(info.encode("utf-8"))
def recv_from_client(self, addr):
"""
接收客戶端信息並轉發給其他客戶端
:param addr:
:return:
"""
while True:
recv_info = self.socket_mapping.get(addr).recv(self.maxSize).decode('utf-8')
print('client{} say: '.format(addr), recv_info)
for i_addr in self.socket_mapping.keys():
if i_addr != addr:
self.socket_mapping.get(i_addr).send(recv_info.encode("utf-8"))
@staticmethod
def modify_mapping(share_var, share_key, share_value, share_lock):
# 獲取鎖
share_lock.acquire()
# 修改數據
share_var[share_key] = share_value
# 釋放鎖
share_lock.release()
if __name__ == "__main__":
my_server = MyServer()
my_server.run()
非同步IO實現socket通信伺服器端代碼
存在的問題:通信時需要相互發送幾次消息後,各自才會收到之前的消息並列印。
import socket
import asyncio
import select
class MyServer(object):
def __init__(self):
# 初始化socket
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 設置伺服器IP地址
host = '192.168.152.1'
# 設置伺服器埠號
port = 4321
# 綁定IP地址和埠
self.server.bind((host, port))
# 設置最大監聽數
self.server.listen(5)
# 設置一個字典,用來保存每一個客戶端的連接和身份信息
self.socket_mapping = {self.server: None} # 這裡存入self.server是為了充當select.select參數
# 設置接收的最大位元組數
self.maxSize = 1024
# 進入事件迴圈
self.loop = asyncio.get_event_loop()
def run(self):
while True:
# select監聽請求對象
rret, _, _ = select.select(self.socket_mapping.keys(), [], [])
for r_socket in rret:
if r_socket is self.server:
socket, addr = r_socket.accept()
# 發送信息,提示客戶端已成功連接
socket.send('success!'.encode('utf-8'))
# 將客戶端socket等信息存入字典
self.socket_mapping[socket] = addr
else:
task = [self.send_to_client(r_socket), self.recv_from_client(r_socket)]
self.loop.run_until_complete(asyncio.gather(*task))
async def send_to_client(self, socket):
"""
獲取鍵盤輸入併發送給客戶端
:param socket:
:return:
"""
info = input()
if info == "quit":
socket.close()
for socket in self.socket_mapping.keys():
if socket != self.server:
socket.send(info.encode("utf-8"))
async def recv_from_client(self, socket):
"""
接收客戶端信息並轉發給其他客戶端
:param socket:
:return:
"""
recv_info = socket.recv(self.maxSize).decode('utf-8')
print('client{} say: '.format(self.socket_mapping[socket]), recv_info)
for i_socket in self.socket_mapping.keys():
if i_socket != socket and i_socket != self.server:
i_socket.send(recv_info.encode("utf-8"))
my_server = MyServer()
my_server.run()
客戶端代碼(使用多線程)
import socket
import threading
class MyClient(object):
def __init__(self):
# 初始化socket
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 設置伺服器IP地址
self.host = '192.168.152.1'
# 設置伺服器埠號
self.port = 4321
# 設置接收的最大位元組數
self.max_size = 1024
def run(self):
# 與伺服器建立連接
self.client.connect((self.host, self.port))
# 創建線程,負責獲取鍵盤輸入併發送給伺服器
threading.Thread(target=self.sned_to_server).start()
# 創建線程,接收伺服器信息
threading.Thread(target=self.recv_from_server).start()
def sned_to_server(self):
"""
獲取鍵盤輸入併發送給伺服器
"""
while True:
send_msg = input()
self.client.send(send_msg.encode('utf-8'))
if send_msg == 'quit':
break
self.client.close()
def recv_from_server(self):
"""
接收伺服器信息
"""
while True:
recv_info = self.client.recv(self.max_size).decode('utf-8')
print('server{} say: '.format((self.host, self.port)), recv_info)
my_client = MyClient()
my_client.run()