Python基础笔记系列十三:socket网络编程
本系列教程供个人学习笔记使用,如果您要浏览可能需要其它编程语言基础(如C语言),why?因为我写得烂啊,只有我自己看得懂!!
使用python编写一个简易的服务端程序和客户端程序,启动服务端和客户端(监听的ip和端口一致),服务端对客户端进行指定Ip和端口的监听,实现接收客户端发送的数据以及对客户端发送数据。
- 使用原生socket
主要运用到python的socket模块,直接使用自己的代码进行socket对象的创建、ip和端口的绑定、接收和发送数据等操作。
服务端:server1.py1 #incoding:utf-8 2 3 #下面这个例子是直接用socket来编程 4 #server1 : 5 from socket import * 6 myhost='127.0.0.1' 7 myport=8080 8 sockobj = socket(AF_INET,SOCK_STREAM) #socket(ip协议,tcp协议) 9 sockobj.bind((myhost,myport)) #绑定ip和端口 10 sockobj.listen(128) #同时允许128个连接 11 while True: #注意True首字母大写,当然也可以写while 1: 12 connection,address = sockobj.accept() #accept()返回两个值,一个连接对象,一个地址 13 print 'connect by',address #打印连接这个服务的地址 14 while True: 15 data = connection.recv(1024) #把接收的数据实例化 16 print '客户端发送过来的数据:'+data#打印一下数据 17 connection.send('yours data:' + data) #回显数据,返回给客户端 18 connection.close() #关闭连接
客户端:client1.py
1 #incoding:utf-8 2 #server1的客户端程序 3 #借鉴:https://blog.csdn.net/rebelqsp/article/details/22109925 4 from socket import * 5 HOST='127.0.0.1' 6 PORT=8080 7 s=socket(AF_INET,SOCK_STREAM) #定义socket类型,网络通信,TCP 8 s.connect((HOST,PORT)) #要连接的IP与端口 9 while 1: 10 cmd=raw_input("Please input cmd:") #与人交互,输入命令 11 s.send(cmd) #把命令发送给服务端端 12 # print help(s) 13 data=s.recv(1024) #把接收的数据定义为变量 14 print data #输出变量 15 s.close() #关闭连接
写好服务端和客户端程序,现在进行测试。
首先启动服务端进行ip端口监听,如果端口被占用,尝试更换端口,范围是0到65535或者停用端口占用,看这里传送门:http://www.cnblogs.com/hyyq/p/6747356.html
服务端启动成功后,启动客户端程序(这里需要输入内容,所以需要安装REPL插件哦,如果没有,看这里传送门:http://www.cnblogs.com/hyyq/p/8909129.html)
这时候在客户端输入数据,并会输出服务端返回的数据,如:1 Please input cmd:123456 2 yours data:123456 3 Please input cmd:abc 4 yours data:abc 5 Please input cmd:
服务端控制台就会输出:
1 connect by ('127.0.0.1', 9848) 2 客户端发送过来的数据:123456 3 客户端发送过来的数据:abc
- 使用socketserver
python也有封装好的可以用,比如:socketserver,可以快速进行一个简单的socket通信。需要导入SocketServer模块的TCPServer,BaseRequestHandler类,然后我们自己的类从BaseRequestHandler继承,并重写handle方法,然后可以很简单的就可以接收发送数据。
服务端:server2.py1 #incoding:utf-8 2 from SocketServer import TCPServer,BaseRequestHandler 3 import traceback 4 #python也有封装好的可以用,比如:socketserver 5 #从BaseRequestHandler继承,并重写handle方法,然后可以很简单的就可以接收发送数据 6 class MyBaseRequestHandler(BaseRequestHandler): 7 ''' 8 从BaseRequestHandler继承,并重写handle方法 9 ''' 10 def handle(self): 11 #循环监听(读取)来自客户端的数据 12 while True: 13 #当客户端主动断开连接时,self.read(1024)会抛出异常 14 try: 15 #一次读取1024字节,并取出两端的空白字符(包括空格,Tab,\r,\n) 16 data = self.request.recv(1024).strip() 17 18 #self.client_address是客户端的连接(host,post)的元组 19 print "receive from (%r):%r"%(self.client_address,data) 20 21 #转换成大写后回写给客户端 22 self.request.sendall(data.upper()+"\n") 23 except: 24 traceback.print_exc() 25 break 26 27 if __name__ == '__main__': 28 #telnet 127.0.0.1 8081 29 host = "127.0.0.1" #主机名,可以是ip,像localhost的主机名或"" 30 port = 8081 #端口 31 addr = (host,port) 32 33 #构造TCPServer对象 34 server = TCPServer(addr, MyBaseRequestHandler) 35 #启动服务监听 36 server.serve_forever()
客户端:client2.py
1 #incoding:utf-8 2 #server2的客户端程序 3 from socket import * 4 HOST='127.0.0.1' 5 PORT=8081 6 s=socket(AF_INET,SOCK_STREAM) #定义socket类型,网络通信,TCP 7 s.connect((HOST,PORT)) #要连接的IP与端口 8 while 1: 9 cmd=raw_input("Please input cmd:") #与人交互,输入命令 10 s.sendall(cmd) #把命令发送给服务端端 11 data=s.recv(1024) #把接收的数据定义为变量 12 print data #输出变量 13 s.close() #关闭连接
依次各自启动服务端、客户端后,客户端输入:
1 Please input cmd:123 2 123 3 4 Please input cmd:456 5 456 6 7 Please input cmd:abc 8 ABC 9 10 Please input cmd:
服务端输出:
1 receive from (('127.0.0.1', 10458)):'123' 2 receive from (('127.0.0.1', 10458)):'456' 3 receive from (('127.0.0.1', 10458)):'abc'
- 多线程TCPServer
上面的两种方式都只支持一个客户端和一个服务端进行通信,如果需要多个客户端和一个服务端通信就需要用到ThreadingTCPServer,StreamRequestHandler,我们自己的类MyStreamRequestHandler从StreamRequestHandler继承,并重写handle方法,然后可以很简单的就可以接收发送数据。
服务端:server3.py1 #incoding:utf-8 2 from SocketServer import ThreadingTCPServer,StreamRequestHandler 3 import traceback 4 #python还可以多个客户端的多线程TCPServer, 5 #从StreamRequestHandler继承,并重写handle方法,然后可以很简单的就可以接收发送数据 6 class MyStreamRequestHandler(StreamRequestHandler): 7 def handle(self): 8 #循环监听(读取)来自客户端的数据 9 while True: 10 print 'begin...' 11 try: 12 # print help(self.rfile) 13 data = self.rfile.readline().strip() 14 15 #self.client_address是客户端的连接(host,post)的元组 16 print "receive from (%r):%r"%(self.client_address,data) 17 18 #转换成大写后回写给客户端 19 self.wfile.write(data.upper()+"\n") 20 except: 21 traceback.print_exc() 22 break 23 24 if __name__ == '__main__': 25 #telnet 127.0.0.1 8080 26 host = "127.0.0.1" #主机名,可以是ip,像localhost的主机名或"" 27 port = 8082 #端口 28 addr = (host,port) 29 30 #ThreadingTCPServer从ThreadingMixIn和TCPServer继承 31 #类结构:class ThreadingTCPServer(ThreadingMixIn,TCPServer):pass 32 server = ThreadingTCPServer(addr, MyStreamRequestHandler) 33 #启动服务监听 34 server.serve_forever()
第一个客户端:client3_1.py
1 #incoding:utf-8 2 #server3的客户端程序1 3 #借鉴:https://blog.csdn.net/rebelqsp/article/details/22109925 4 from socket import * 5 HOST='127.0.0.1' 6 PORT=8082 7 s=socket(AF_INET,SOCK_STREAM) #定义socket类型,网络通信,TCP 8 s.connect((HOST,PORT)) #要连接的IP与端口 9 while 1: 10 cmd=raw_input("Please input cmd:") #与人交互,输入命令 11 #注意:发送的字符串内容要加一个回车符即\r\n 12 #因为服务端server3是根据行来读取的 13 s.sendall("%s\r\n"%cmd) #把命令发送给服务端端 14 # print help(s) 15 data=s.recv(1024) #把接收的数据定义为变量 16 print data #输出变量 17 s.close() #关闭连接
第二个客户端:client3_2.py
1 #incoding:utf-8 2 #server3的客户端程序2 3 from socket import * 4 HOST='127.0.0.1' 5 PORT=8082 6 s=socket(AF_INET,SOCK_STREAM) #定义socket类型,网络通信,TCP 7 s.connect((HOST,PORT)) #要连接的IP与端口 8 while 1: 9 cmd=raw_input("Please input cmd:") #与人交互,输入命令 10 #注意:发送的字符串内容要加一个回车符即\r\n 11 #因为服务端server3是根据行来读取的 12 s.sendall("%s\r\n"%cmd) #把命令发送给服务端端 13 data=s.recv(1024) #把接收的数据定义为变量 14 print data #输出变量 15 s.close() #关闭连接
依次启动服务端和两个客户端,这个时候不论是在客户端1还是客户端2输入,服务端都可以接收并反馈消息。
服务端控制台打印(客户端控制台不展示了):1 begin... 2 receive from (('127.0.0.1', 10989)):'def' 3 begin... 4 begin... 5 receive from (('127.0.0.1', 11015)):'poi' 6 begin... 7 receive from (('127.0.0.1', 10989)):'abc' 8 begin...