我学习网络编程,并希望用Python编写一个简单的命令行聊天。
我想知道如何随时随地输入可用于发送的接收。
如您所见,此客户端一次只能完成一项工作:
from socket import *
HOST = 'localhost'
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST, PORT)
tcpCliSock = socket(AF_INET, SOCK_STREAM)
tcpCliSock.connect(ADDR)
while 1:
data = raw_input('> ')
if not data: break
tcpCliSock.send(data)
data = tcpCliSock.recv(BUFSIZE)
if not data: break
print data
tcpCliSock.close()
因此,如果另一个客户端发送消息,则此客户端仅在发送消息后才会收到消息。我打赌你了解我。我搜索了这个问题,发现了很多有趣的东西,比如异步I / O,线程,非阻塞同步,并发编程等等。我也安装了扭曲的包装。简而言之,我一直在学习所有这些东西但却找不到我想要的东西。 (当然,我会一直努力尝试,直到我达到目的。)
所以,我的问题是如何制作的? =)
答案 0 :(得分:8)
你的问题不是很紧密。但是,您的程序根本不需要异步即可达到您的要求。
这是您最初想要的最小变化的工作聊天脚本。它使用1个线程进行接收,1个用于发送,两者都使用阻塞套接字。它比使用异步方法简单得多。
from socket import *
from threading import Thread
import sys
HOST = 'localhost'
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST, PORT)
tcpCliSock = socket(AF_INET, SOCK_STREAM)
tcpCliSock.connect(ADDR)
def recv():
while True:
data = tcpCliSock.recv(BUFSIZE)
if not data: sys.exit(0)
print data
Thread(target=recv).start()
while True:
data = raw_input('> ')
if not data: break
tcpCliSock.send(data)
tcpCliSock.close()
答案 1 :(得分:5)
如果您想从头开始编码select
,那么就可以了(您可以在Google图书搜索中阅读包含此类问题的Nutshell中Python的大部分内容);如果你想利用更多的抽象,asyncore
是可用的,但Twisted更丰富,更强大。
答案 2 :(得分:2)
聊天程序同时做两件事。
观看本地用户的键盘并发送给远程用户(通过某种插座)
观看远程套接字并在本地控制台上显示他们输入的内容。
你有几种方法可以做到这一点。
打开套接字和键盘的程序,使用select模块查看哪个模块已准备就绪。
创建两个线程的程序。一个线程读取远程套接字并打印。另一个线程读取键盘并发送到远程套接字。
分叉两个子进程的程序。一个子进程读取远程套接字并打印。另一个子进程读取键盘并发送到远程套接字。
答案 3 :(得分:2)
嗯,好吧,这就是我现在所拥有的。
服务器是这样的:
import asyncore
import socket
clients = {}
class MainServerSocket(asyncore.dispatcher):
def __init__(self, port):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.bind(('',port))
self.listen(5)
def handle_accept(self):
newSocket, address = self.accept( )
clients[address] = newSocket
print "Connected from", address
SecondaryServerSocket(newSocket)
class SecondaryServerSocket(asyncore.dispatcher_with_send):
def handle_read(self):
receivedData = self.recv(8192)
if receivedData:
every = clients.values()
for one in every:
one.send(receivedData+'\n')
else: self.close( )
def handle_close(self):
print "Disconnected from", self.getpeername( )
one = self.getpeername( )
del clients[one]
MainServerSocket(21567)
asyncore.loop( )
客户就是这样:
from Tkinter import *
from socket import *
import thread
HOST = 'localhost'
PORT = 21567
BUFSIZE = 1024
ADDR = (HOST, PORT)
tcpCliSock = socket(AF_INET, SOCK_STREAM)
tcpCliSock.connect(ADDR)
class Application(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.grid()
self.create_widgets()
self.socket()
def callback(self, event):
message = self.entry_field.get()
tcpCliSock.send(message)
def create_widgets(self):
self.messaging_field = Text(self, width = 110, height = 20, wrap = WORD)
self.messaging_field.grid(row = 0, column = 0, columnspan = 2, sticky = W)
self.entry_field = Entry(self, width = 92)
self.entry_field.grid(row = 1, column = 0, sticky = W)
self.entry_field.bind('<Return>', self.callback)
def add(self, data):
self.messaging_field.insert(END, data)
def socket(self):
def loop0():
while 1:
data = tcpCliSock.recv(BUFSIZE)
if data: self.add(data)
thread.start_new_thread(loop0, ())
root = Tk()
root.title("Chat client")
root.geometry("550x260")
app = Application(root)
root.mainloop()
现在是时候让代码看起来更好并添加一些功能。
感谢您的帮助,伙计们!
答案 4 :(得分:1)
答案 5 :(得分:1)
我在异步I / O中编写了一个...它比完整的线程模型更容易包围你。
如果你能得到“谈话”的源代码,你可以学到很多东西。看一个演示http://dsl.org/cookbook/cookbook_40.html#SEC559,或者如果你在linux盒子上那就试试吧......
它实时发送字符。
另外,ytalk是互动式和多个用户....有点像hudddlechat或篝火。