简单的socket代码和多线程练习
用socket服务端和多线程实现可以连接多个客户端并同时收发的功能。
这里要用到socket 和 threading
所以,记得:
import socket, threading
一、创建socket服务端
首先,按正常操作,创建一个socket,选择ipv4和数据流:
socketServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
通过socket模块获取本地ip,并绑定ip和端口号,设置监听数量:
socketServer.bind((socket.gethostbyname(socket.gethostname()), 8080))
socketServer.listen(5) #这里监听数量和创建的接收线程数应保持一致
然后设置两个全局变量,以便线程中的得到的客户端信息和ip传出,方便选择发送信息
global Cilents, addrips
Cilents = []
addrips = []
二、多线程
考虑到多个客户端连接,就需要把等待连接、接收信息、发送信息其中两个个丢到多线程中,我选择把发送信息放在主线程,并在等待连接的进程中再创建接收信息的进程:
def waitFaccept():
while True:
Cilent1, addrip = socketServer.accept()
Cilents.append(Cilent1)
addrips.append(addrip)
for i in range(len(addrips)):
print('%d:%s' % (i+1, addrips[i][0]))
while threading.active_count() > 6:
pass
t = threading.Thread(target=receive, args=(Cilent1, addrip))
t.start()
def receive(socketServer, addrip):
while True:
try:
content = socketServer.recv(1024)
if len(content) != 0:
print('收到客户端%d号%s的消息:%s' % (Cilents.index(socketServer) + 1, addrip[0], content.decode('utf-8')))
except ConnectionResetError:
socketServer.close()
print('与%s的连接已断开!' % addrip[0])
addrips.remove(addrip[0])
Cilents.remove(socketServer)
for i in range(len(addrips)):
print('%d:%s' % (i+1, addrips[i][0]))
break
threading的用法就不用多说了吧,传函数和参数,然后start就搞定了
三、主线程后续
然后接着写主线程部分的内容:
threading.Thread(target=waitFaccept).start()
while True:
if threading.active_count() > 2:
break
# 接收数据
while True:
while True:
for i in range(len(addrips)):
print(' %d : %s' % (i+1, addrips[i][0]))
setnum = input('请输入客户端编号:')
try:
setnum = int(setnum) - 1
except ValueError:
print('%s error\r\n请输入一个数字!' % setnum)
continue
if setnum < len(Cilents) and setnum >= 0:
break
else:
print('请输入范围内的编号!!', end='\r')
content = input('给%s发送的内容:' % (addrips[setnum][0]))
# Cilent1.sendall(str.encode(content))
try:
Cilents[setnum].sendall(content.encode('utf-8'))
except ConnectionResetError:
if Cilents[setnum] in Cilents:
Cilents.remove(Cilents[setnum])
addrips.remove(addrips[0][0])
Cilents[setnum].close()
写完需要丢到多线程中的等待连接和接收数据函数后,启动等待连接函数的线程,用while阻塞主线程,利用threading.active_count()的方法获取线程数来判断是否有客户端连接进来。等待客户端连接之后继续运行主线程,根据global中储存的客户端,就可以愉快的选择发送信息了。PS:后面的细节部分写的不是特别好,如果接收到数据命令行会显得很乱,不过并不影响发送。
如果不想研究可以自己下载玩一玩:https://download.csdn.net/download/an195/10472725