UDP聊天服务器也可以聊天
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UDP聊天服务器也可以聊天相关的知识,希望对你有一定的参考价值。
我在GitHub上发现了一个非常简单的开源project:相同的Python脚本可以用作服务器或客户端。
import socket
import threading
import queue
import sys
import random
import os
#Client Code
def ReceiveData(sock):
while True:
try:
data,addr = sock.recvfrom(1024)
print(data.decode('utf-8'))
except:
pass
def RunClient(serverIP):
host = socket.gethostbyname(socket.gethostname())
port = random.randint(6000,10000)
print('Client IP->'+str(host)+' Port->'+str(port))
server = (str(serverIP),5000)
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.bind((host,port))
name = input('Please write your name here: ')
if name == '':
name = 'Guest'+str(random.randint(1000,9999))
print('Your name is:'+name)
s.sendto(name.encode('utf-8'),server)
threading.Thread(target=ReceiveData,args=(s,)).start()
while True:
data = input()
if data == 'qqq':
break
elif data=='':
continue
data = '['+name+']' + '->'+ data
s.sendto(data.encode('utf-8'),server)
s.sendto(data.encode('utf-8'),server)
s.close()
os._exit(1)
#Client Code Ends Here
#Server Code
def RecvData(sock,recvPackets):
while True:
data,addr = sock.recvfrom(1024)
recvPackets.put((data,addr))
def RunServer():
host = socket.gethostbyname(socket.gethostname())
port = 5000
print('Server hosting on IP-> '+str(host))
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.bind((host,port))
clients = set()
recvPackets = queue.Queue()
print('Server Running...')
threading.Thread(target=RecvData,args=(s,recvPackets)).start()
while True:
while not recvPackets.empty():
data,addr = recvPackets.get()
if addr not in clients:
clients.add(addr)
continue
clients.add(addr)
data = data.decode('utf-8')
if data.endswith('qqq'):
clients.remove(addr)
continue
print(str(addr)+data)
for c in clients:
if c!=addr:
s.sendto(data.encode('utf-8'),c)
s.close()
#Serevr Code Ends Here
if __name__ == '__main__':
if len(sys.argv)==1:
RunServer()
elif len(sys.argv)==2:
RunClient(sys.argv[1])
else:
print('Run Serevr:-> python Chat.py')
print('Run Client:-> python Chat.py <ServerIP>')
正如您在图片中看到的那样,它的效果非常好:
但我的目标是让服务器加入聊天。
UDP聊天室是否有可能让服务器在作为服务器工作时充当客户端?
要使服务器也运行客户端,您可以在代码的RunServer()
部分中调用__main__
之前插入此行:
threading.Thread(target=RunClient,args=('127.0.0.1',)).start()
这将启动一个与服务器的事件循环并行运行RunClient('127.0.0.1')
的线程。
但是,在此代码正常工作之前,您还需要修复其他一些代码问题。特别是:
在RunServer()
的顶部,您将host
设置为服务器计算机上某个网络接口卡的IP地址。这意味着服务器只能接受该网络接口上的传入TCP连接,这意味着(除非该网络接口恰好是内部/环回接口),服务器将不接受来自其自身客户端的127.0.0.1
连接-线。简单的解决方法是简单地将host
设置为空字符串,这样服务器将接受所有本地网络接口上的传入TCP连接,问题就会消失。
def RunServer():
host = '' # was: socket.gethostbyname(socket.gethostname())
[...]
第二个问题是您的服务器的事件循环正忙等待,导致服务器进程在其运行的整个时间内不必要地占用100%的CPU核心。这非常低效。这个问题的原因在这里,在RunServer()
内:
while True:
while not recvPackets.empty():
data,addr = recvPackets.get()
[...]
请注意,在Python Queue
类中,调用get()
会阻塞,直到有更多数据要接收,从而阻止CPU旋转。但是在上面的代码中,get()
永远不会被调用,除非/直到recvPackets
非空,所以线程永远不会阻塞。
修复很简单,只需完全删除while not recvPackets.empty()
行,这样即使Queue为空,也会调用get()
。 get()
在有数据返回之前不会返回。
while True:
data,addr = recvPackets.get()
[...]
以上是关于UDP聊天服务器也可以聊天的主要内容,如果未能解决你的问题,请参考以下文章