http://czug.org/blog/eishn/python-jishupeixun-disanzhoujiangyi
简单的网络通信及即时聊天
今天是网络编程。不妨做一个即时聊天工具吧, 不过这次的程序很简陋, 只能说是一个网络对讲机罢了。
今天我不准备去讲更底层的东西, 比如使用 Socket 来编写通信程序。不过以后, 可能就是下次我们就会涉及到。
然而, 今天的东西相当有用。在没有必要钻牛角尖的时候 (这是大多数的情况), 今天所用到的方法几乎是第一选择。使用 XMLRPC 来进行网络编程, 确实出奇的简单。但是请注意, 千万不要被现在国内的风气给误导了, 其实使用简单的工具来进行编程并不愚蠢, 相反是你聪明的表现。而且, 复杂的应用通常是用最简单的方法建立的, 如果妄图使用石器时代的工具来建造高楼大厦, 那几乎是不可能的。
下面先来个服务器。
from SimpleXMLRPCServer import SimpleXMLRPCServer
def foo():
return "Hello world!"
server = SimpleXMLRPCServer( ("localhost", 8000) )
server.register_function(foo)
server.serve_forever()
用 IE 来访问 http://localhost:8000 看看我们得到了什么? 是一个出错页面, 不错, 这表示我们的服务器工作正常, 只是访问的方法不对而已。
下面, 给出这个程序的客户机程序。
from xmlrpclib import ServerProxy
server = ServerProxy("http://localhost:8000")
print server.foo()
我们会看到服务器返回了 "Hello world!"。这里 localhost 是指本机, 8000 是端口, 我们通常会指定大于 1024 的端口号。localhost 我们通常会用域名 (机器名) 或 IP 来代替, 而端口号是任意的。
下面, 该传些东西了。比如发送一句话到服务器上去显示出来。
from SimpleXMLRPCServer import SimpleXMLRPCServer
def msg(s):
print s
return True
server = SimpleXMLRPCServer( ("localhost", 8000) )
server.register_function(msg)
server.serve_forever()
对应的客户机程序。
from xmlrpclib import ServerProxy
server = ServerProxy("http://localhost:8000")
while True:
msg = raw_input()
server.msg(msg)
开个玩笑, 一个即时通信工具已经写好了。两台机器互相知道 IP 或者机器名, 协商好端口号。然后打开一个服务器、将客户机指向对方的服务器就可以了。
那么怎么将客户端和服务器合并在一起呢? 因为调用 serve_forever() 之后程序就停在那里了, 所以无法再接收用户输入的东西了。这里顺便讲一下多线程编程, 但是这个话题不在本次主题之内, 大家仅做理解就可以了。
import thread
from SimpleXMLRPCServer import SimpleXMLRPCServer
from xmlrpclib import ServerProxy
def msg(s):
print s
return True
def run_server():
my_server = SimpleXMLRPCServer( ("localhost", 8001) )
my_server.register_function(msg)
my_server.serve_forever()
def run_client():
your_server = ServerProxy("http://localhost:8002")
while True:
msg = raw_input()
your_server.msg(msg)
thread.start_new_thread( run_server, () )
run_client()
第二个差不多, 只是把互相的地址换了一下而已。
import thread
from SimpleXMLRPCServer import SimpleXMLRPCServer
from xmlrpclib import ServerProxy
def msg(s):
print s
return True
def run_server():
my_server = SimpleXMLRPCServer( ("localhost", 8002) )
my_server.register_function(msg)
my_server.serve_forever()
def run_client():
your_server = ServerProxy("http://localhost:8001")
while True:
msg = raw_input()
your_server.msg(msg)
thread.start_new_thread( run_server, () )
run_client()
这样, 一对对讲机就写好了。
接下来就要用到我上一次讲到的图形界面的知识, 用 Tkinter 来写一个界面了。
首先把窗体画出来。
from Tkinter import *
wnd = Tk()
wnd.lab = Label(wnd, text="---")
wnd.ent = Entry(wnd)
wnd.btn = Button(wnd, text="send")
wnd.lab.pack()
wnd.ent.pack(side=LEFT)
wnd.btn.pack(side=LEFT)
然后把刚才的网络部分加上去。
import thread
from SimpleXMLRPCServer import SimpleXMLRPCServer
from xmlrpclib import ServerProxy
# 第一个对讲机
my_server = SimpleXMLRPCServer( ("localhost", 8002) )
your_server = ServerProxy("http://localhost:8001")
# 第二个对讲机 (需要交换一下地址)
# my_server = SimpleXMLRPCServer( ("localhost", 8001) )
# your_server = ServerProxy("http://localhost:8002")
def msg(s):
wnd.lab.config(text=s)
return True
def run_server():
my_server.register_function(msg)
my_server.serve_forever()
def send():
msg = wnd.ent.get()
wnd.ent.select_range(0, len(msg))
your_server.msg(msg)
wnd.btn.config(command=send)
thread.start_new_thread( run_server, () )
wnd.mainloop()
因为程序比较长, 所以另外一个终端就不写了。注意, 这里两台终端的地址是在程序中写死的。而且现在的程序只能显示最近收到的一条消息。
·我们可以使用 Tkinter 中的输入框来叫用户自己输入目标机器的地址和端口。
·我们可以使用 Tkinter 中的编辑框组件来显示多行消息。
这个作为这次的作业。我的意思是完善这个聊天程序, 做成比较漂亮的样子。同时思考一下如何来实现一个多人聊天室。
下周可能会涉及到 Socket, 请预习一下。