1、TCP编程
2、SocketServer模块
3、Twisted框架
4、UDP编程
1、TCP编程——TCP是面向连接的,其一般的设计如下:
# encoding:utf-8 ‘‘‘ Created on 2014-6-20 @author: Administrator ‘‘‘ from socket import socket, AF_INET, SOCK_STREAM import time import threading class SockServer(object): def __init__(self, port): self.HOST = "localhost" self.PORT = port self.SOCK = (self.HOST, self.PORT) self.BUF = 1024 self._init() def _init(self): self.sock_server = socket(AF_INET, SOCK_STREAM) self.sock_server.bind(self.SOCK) self.sock_server.listen(100) def __thread_process(self, sock_client, client_addr): print "connected :", sock_client.getpeername() while True: data = sock_client.recv(self.BUF) if not data: continue elif data == "bye": print "<< %s" % data break else: sock_client.send(‘[%s] %s‘ % (time.ctime(), data)) print "%s << %s: %s" % (sock_client.getsockname(), client_addr, data) sock_client.close() """多线程并发服务器""" def process(self): while True: print "waiting for connection..." (sock_client, client_addr) = self.sock_server.accept() threading.Thread(target=self.__thread_process, args=(sock_client, client_addr)).start() def __del__(self): self.sock_server.close() if __name__ == "__main__": port = 12345 server = SockServer(port) server.process()
客户端一般设计:
# encoding:utf-8 ‘‘‘ Created on 2014-6-20 @author: Administrator ‘‘‘ from socket import socket, AF_INET, SOCK_STREAM class SockClient(object): def __init__(self, ip, port): self.IP = ip self.PORT = port self.SOCK = (ip, port) self.BUF = 1024 self._init() def _init(self): self.sock_client = socket(AF_INET, SOCK_STREAM) def process(self): print "connecting server..." self.sock_client.connect(self.SOCK) while True: data = raw_input(">>") self.sock_client.send(data) if data.strip() == "bye": break recv_data = self.sock_client.recv(self.BUF) if not recv_data: print "no recv!" else: print recv_data def __del__(self): self.sock_client.close() if __name__ == "__main__": ip = "localhost" port = 12345 client = SockClient(ip, port) client.process()
2、SocketServer模块——用于简化实现网络编程客户端与服务器所需要的大量样板代码。
2.1 创建一个SocketServerTCP服务器:
# encoding:utf-8 ‘‘‘ Created on 2014-6-23 @author: Administrator ‘‘‘ from time import ctime from SocketServer import TCPServer, StreamRequestHandler """ SocketServer 的请求处理器默认行为时接收连接,得到请求,然后关闭连接,这使得我们不能 在程序运行时,一直保持连接状态,而是每次发送数据到服务器的时候创建一个新的套接字 """ class MyRequestHandle(StreamRequestHandler): """ 客户端有消息发来时,handle函数会被调用 """ def handle(self): print "...connecting from :", self.client_address self.wfile.write(‘[%s] %s‘ % (ctime(), self.rfile.readline())) if __name__ == "__main__": ip = "localhost" port = 12345 tcpServ = TCPServer((ip, port), MyRequestHandle) print "waiting for connection..." tcpServ.serve_forever()
说明:
1、这里的主要工作是从SocketServer的StreamRequestHandler类派生出一个子类,并重写handle()函数。
在有客户端消息近来的时候,handle()函数就会被调用,如上是一个使用SocketServer模块的回射服务器例子。
2、SocketServer的请求处理器的默认行为时接收连接,得到请求,然后关闭连接,这使得我们不能再程序运行时,一致保持连接状态,
而是每次发送数据到服务器的时候都要创建一个新的套接字。
2.2 创建一个SocketServerTCP客户端:
# encoding:utf-8 ‘‘‘ Created on 2014-6-23 @author: Administrator ‘‘‘ from socket import socket, AF_INET, SOCK_STREAM class SocketClient(object): def handle(self, ADDR): BUF = 1024 while True: self.client = socket(AF_INET, SOCK_STREAM) self.client.connect(ADDR) data = raw_input(">>") if not data: break self.client.send("%s\r\n" % data) #服务端使用的是readline,为了保持一致,发送添加了换行 rcv_data = self.client.recv(BUF) if not rcv_data: break else: print rcv_data.strip() self.client.close() self.client.close() if __name__ == "__main__": ip = "localhost" port = 12345 client = SocketClient() client.handle((ip, port))
说明:
1、本例子是针对使用SocketServer的服务端的例子,其中send()函数需要添加”\r\n”换行符,对应于服务器端的readline()函数
2、发送数据之后,断开连接,因为SocketServer的默认行为使得不能再程序运行时,一致保持连接状态
运行结果:
服务端:
客户端:
3、Twisted框架
简介——Twisted是一个完全事件驱动的网络框架,允许使用和开发完全异步的网络应用程序和协议。
3.1 安装Twisted扩展(Windows)
下载:Twisted和zope
http://twistedmatrix.com/trac/wiki/Downloads
安装Twisted扩展(Linux)
命令:easy_install twisted
eclipse pydev添加twisted模块:
系统已经安装twisted模块,导入twisted,引用其中的方法时,出现如下情况:
解决方法是:
在Eclipse的Window—Preferences—PyDev—Interpreter-Python 窗口下的Forced Buildins添加twisted
即可正常引用twisted包
3.2 Twisted服务端:
# encoding:utf-8 ‘‘‘ Created on 2014-6-23 @author: Administrator ‘‘‘ from twisted.internet import reactor, protocol from time import ctime """ Twisted 是一个完全事件驱动的网络框架,允许使用和开发完全异步的网络应用程序和协议 """ class TwistedServer(protocol.Protocol): """ 重写connectionMade函数,该函数在有客户端连接时被调用 """ def connectionMade(self): client = self.client = self.transport.getPeer().host print "...connected from ", client, ":", self.transport.getPeer().port """ 该函数在客户端通过网络发送数据过来时被调用 """ def dataReceived(self, data): self.transport.write("[%s] %s" % (ctime(), data)) if __name__ == "__main__": port = 12345 factory = protocol.Factory() factory.protocol = TwistedServer print "waiting for connection..." reactor.listenTCP(port, factory) reactor.run()
说明:
Twistede服务端从Protocol类派生子类,然后重写connectionMade()函数,这个函数在有客户端连接的时候被调用,dataReceived()函数,这个函数在客户端
通过网络发送数据过来的时候被调用,reactor把数据当成参数传到这个函数中
3.3 Twisted客户端
# encoding:utf-8 ‘‘‘ Created on 2014-6-23 @author: Administrator ‘‘‘ from twisted.internet import protocol, reactor class TwistedClient(protocol.Protocol): def _senddata(self): data = raw_input(">>") if data: print "...sending %s..." % data self.transport.write(data) else: self.transport.loseConnection() #连接建立之后,调用自定义_senddata函数 def connectionMade(self): self._senddata() def dataReceived(self, data): print data self._senddata() class TClientFactory(protocol.ClientFactory): protocol = TwistedClient clientConnectionLost = clientConnectionFailed = lambda self, connector, reason:reactor.stop() if __name__ == "__main__": host = "localhost" port = 12345 reactor.connectTCP(host, port, TClientFactory()) reactor.run()
说明:
Twisted客户端也从Protocol派生子类,重写connectionMade()和dataReceived()函数,当用户没有任何输入时(参考如上代码中_senddata()函数中else部分),连接结束,结束时,调用loseConnection关闭套接字,这时工厂的clientConnectionLost函数会被调用,同时reactor就被关闭,脚本执行就结束了,由于某些原因,clientConnectionFailed()被调用时,reactor也会被关闭。
4. UDP 编程
UDP是无连接的,服务器一般设计如下:
4.1 服务器端编程
# encoding:utf-8 ‘‘‘ Created on 2014-6-20 @author: Administrator ‘‘‘ from socket import socket, AF_INET, SOCK_DGRAM from time import ctime class DgramServer(object): def __init__(self, port): self.HOST = "localhost" self.PORT = port self.SOCK = (self.HOST, self.PORT) self.BUF = 1024 self._init() def _init(self): self.dgram_server = socket(AF_INET, SOCK_DGRAM) self.dgram_server.bind(self.SOCK) def process(self): print "waiting for message..." while True: data, addr = self.dgram_server.recvfrom(self.BUF) print "<<",addr, ":%s " % data if data == "bye": break self.dgram_server.sendto("[%s,%s]" % (ctime(), data), addr) def __del__(self): self.dgram_server.close() if __name__ == "__main__": port = 12345 dgram = DgramServer(port) dgram.process()
注意:
UDP服务端,recvfrom会返回连接的地址
4.2 客户端编程
# encoding:utf-8 ‘‘‘ Created on 2014-6-20 @author: Administrator ‘‘‘ from socket import socket, AF_INET, SOCK_DGRAM class DgramClient(object): def __init__(self, ip, port): self.HOST = ip self.PORT = port self.SOCK = (self.HOST, self.PORT) self.BUF = 1024 self._init() def _init(self): self.dgram_client = socket(AF_INET, SOCK_DGRAM) def process(self): while True: data = raw_input("<<") self.dgram_client.sendto(data, self.SOCK) if data == "bye": break recv_data, dgram = self.dgram_client.recvfrom(self.BUF) if not recv_data: print "no recv" else: print ">>", dgram, ":%s" % recv_data def __del__(self): self.dgram_client.close() if __name__ == "__main__": ip = "localhost" port = 12345 dgram = DgramClient(ip, port) dgram.process()
运行结果:
服务端:
客户端1:
客户端2: