1、TCP sorcket:
server side(服务器端):
1 import SocketServer 2 class MyTCPHandler(SocketServer.BaseRequestHandler): 3 def handle(self): 4 self.data=self.request.recv(1024).strip() 5 print "{} wrote".format(self.client_address[0]) 6 print self.data 7 self.request.sendall(self.data.upper()) 8 if __name__=="__main__": 9 HOST,PORT="localhost",9999 10 server=SocketServer.TCPServer((HOST,PORT),MyTCPHandler) 11 server.serve_forever()
解释:
第1句引进相关模块;
第2句定义类MyTCPHandler,它是继承自SocketServer的BaseRequestHandler类,该类还有相关的子类,下面会用到;
第3句重写基类的handle()方法,有很多属性可以直接用,比如self.request,请求,self.request.recv(1024).strip()的意思是从客户端的请求那得到最大1kb的数据,并且数据.strip(),去掉前后的空格,中间的不会去掉的;
self.client_adress是客户端的地址;
第7句是把得到的数据转换成大写发给客户端;
第8句是只有在直接运行当前程序是才会运行到的;
HOST、PORT是主机地址和端口号;
第10句就是创建一个server对象,是基于TCPServer类创建的;
11句是启动服务监听的意思;
上面是一种创建TCP server的方法,下面还有一种基于BaseRequestHandler基类StreamRequestHandler,当然它还有一个基类DatagramRequestHandler,两者有区别。
1 import SocketServer 2 class MyTCPHandler(SocketServer.StreamRequestHandler): 3 def handle(self): 4 self.data=self.rfile.readline().strip() 5 print "{} wrote".format(self.client_address[0]) 6 print self.data 7 self.wfile.write(self.data.upper()) 8 if __name__=="__main__": 9 HOST,PORT="localhost",9999 10 server=SocketServer.TCPServer((HOST,PORT),MyTCPHandler) 11 server.serve_forever()
基本上与上面的相同,但是毕竟StreamRequestHandler是BaseRequestHandler的基类,所以有一些新的方法。
第4行,self.rfile.readline(), self.rfile类型是socket._fileobject,读写模式是"rb",方法有:read,readline,readlines,write(data),writelines(list),close,flush
readline()方法会多次调用recv()方法,直到读取一行;其它的基本类似。
the client side(客户端)
1 import socket 2 import sys 3 HOST,PORT="localhost",9999 4 data=" ".join(sys.argv[1:]) 5 sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 6 try: 7 sock.connect((HOST,PORT)) 8 sock.sendall(data+" ") 9 received=sock.recv(1024) 10 finally: 11 sock.close() 12 print "Sent: {}".format(data) 13 print "Received: {}".format(received) 14 input()
重点:建立一个socket对象sock,socket.SOCK_STREAM说明建立的是一个TCP socket,用socket.SOCK_DGRAM是UDP socket。
sock.connect()方法是与主机建立连接,可见tcp协议是面向连接的可靠地通信协议,这正是tcp与udp协议的不同,udp协议是非面向连接的不可靠的协议,udp发送数据之前并不会与对方建立连接,而是直接发给对方。UDP适用于一次只传送少量数据、对可靠性要求不高的应用环境。
比如,我们经常使用“ping”命令来测试两台主机之间TCP/IP通信是否正常,其实“ping”命令的原理就是向对方主机发送UDP数据包,然后对方主机确认收到数据包,如果数据包是否到达的消息及时反馈回来,那么网络就是通的。例如,在默认状态下,一次“ping”操作发送4个数据包。大家可以看到,发送的数据包数量是4包,收到的也是4包(因为对方主机收到后会发回一个确认收到的数据包)。这充分说明了UDP协议是面向非连接的协议,没有建立连接的过程。正因为UDP协议没有连接的过程,所以它的通信效率高;但也正因为如此,它的可靠性不如TCP协议高。
QQ就使用UDP发消息,因此有时会出现收不到消息的情况。
下面我们就用python来实现UDP的通信协议。
udp服务器端:
1 import SocketServer 2 class MyUDPHandler(SocketServer.BaseRequestHandler): 3 def handle(self): 4 data=self.request[0].strip() 5 socket=self.request[1] 6 print "{} wrote".format(self.client_address[0]) 7 print data 8 socket.sendto(data.upper(),self.client_address) 9 if __name__=="__main__": 10 HOST,PORT="localhost",9999 11 server =SocketServer.UDPServer((HOST,PORT),MyUDPHandler) 12 server.serve_forever()
解释:udp的server与tcp的有一定的区别,它的self.request含有一个data和一个socket,分别用self.request[0]和self.request[1]获取,由于udp是面向非连接的协议,所以要用sendto()方法,并且要加上客户端的地址。
udp客户端:
1 import socket 2 import sys 3 HOST,PORT="localhost",9999 4 data=" ".join(sys.argv[1:]) 5 sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) 6 sock.sendto(data+" ",(HOST,PORT)) 7 received=sock.recv(1024) 8 print "Sent: {}".format(data) 9 print "Received: {}".format(received)
可以看出与tcp的客户端相比,udp的sock并没有连接过程,直接发送的数据。
运行,点击运行服务器端.py的文件,然后在命令行下:python d:/py/client.py hello world (根据自己的文件地址写命令)回车就ok了,可以看到客户端服务器端都有输出数据。