不管哪种语言,都有相对应的网络编程Socket API,如C++的SOCKET,Java的Socket与ServerSocket,当然,Python也不例外,下面看我细细道来。
Python 提供了两个级别访问的网络服务:
- 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的全部方法。
- 高级别的网络服务模块 SocketServer, 它提供了服务器中心类,可以简化网络服务器的开发。
Socket
socket()函数
Python 中,我们用 socket()函数来创建套接字,语法格式如下:
socket.socket([family[, type[, proto]]])
参数
- family: 套接字家族可以使AF_UNIX或者AF_INET
- type: 套接字类型可以根据是面向连接的还是非连接分为SOCK_STREAM或SOCK_DGRAM
- protocol: 一般不填默认为0.
Socket 对象(内建)方法
例子
服务器必须进行这些顺序操作来服务:socket(), bind(), listen(), accept() (如果不止一台客户端,可能需要重复 accept() ), 而客户端只需要进行以下序列的操作 socket(), connect().
Demo for TCP:
TCP服务端
import socket
import threading
server_ip="127.0.0.1"
server_port=9999
def tcp_server(ip,port):
#建立socket对象
server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#绑定ip与port
port = int(port)
server.bind((ip,port))
#监听,最大允许5个进程
server.listen(5)
print "[*] Listing on %s:%d" % (ip,port)
#与多线程的方式处理接入的客户端
while True:
client,addr=server.accept()
print "[*] Accepted connection from:%s:%d" % (addr[0],addr[1])
client_handle=threading.Thread(target=handle_client,args=(client,))
client_handle.start()
def handle_client(client):
pass
response=client.recv(1024)
print "[*] Received:%s" % response
#给客户发送一个接收成功提示
client.send("ACK!")
if __name__ == '__main__':
tcp_server(server_ip, server_port)
TCP 客户端
import socket
target_host="127.0.0.1"
target_port=9999
send_data="GET / HTTP/1.1\r\nHost:%s\r\n\r\n" % target_host
def tcp_client(host,port,data):
#建立一个socket对象
client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#连接服务器
client.connect((host,port))
#向服务器发送数据
client.send(data)
#接收服务器返回的数据
response=client.recv(4096)#最大接收4096字节
print response
if __name__ == '__main__':
#print send_data
tcp_client(target_host, target_port, send_data)
运行结果:
Demo for UDP
UDP服务端
import socket
import threading
server_ip="127.0.0.1"
server_port=9999
def udp_server(ip,port):
#建立socket对象
server=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#绑定ip与port
port = int(port)
server.bind((ip,port))
print "[*] Listing on %s:%d" % (ip,port)
while True:
data,addr=server.recvfrom(1024)
print "[*] Accepted connection from:%s:%d" % (addr[0],addr[1])
print "[*] Received:%s" % data
server.sendto("UDP Connection !",addr)
UDP客户端
import socket
target_host="127.0.0.1"
target_port=9999
send_data="GET / HTTP/1.1\r\nHost:%s\r\n\r\n" % target_host
def udp_client(host,port,data):
#建立一个socket对象
client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#连接服务器并发送数据
client.sendto(data,(target_host,target_port))
#接收服务器返回的数据
response=client.recvfrom(4096)[0]
print response
if __name__ == '__main__':
#print send_data
udp_client(target_host, target_port, send_data)
运行结果:
Demo for 原始套接字
这里只演示抓取一个数据包,话不多说,直接上代码:
import socket
import os
host = "192.168.1.101"
# 创建原始套接字,然后绑定在公开接口上
if os.name == "nt":
socket_protocol = socket.IPPROTO_IP
else:
socket_protocol = socket.IPPROTO_ICMP
#使用原始套接字SOCK_RAW创建socket,用于监听网络数据包
sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)
#这里端口为0,监听所有端口
sniffer.bind((host,0))
# 设置在捕获的数据包中包含IP头
sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
# 在Windows平台上,我们需要设置IOCTL以启用混杂模式
if os.name == "nt":
sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
# 读取单个数据包
print sniffer.recvfrom(65565)
# 在Windows平台上关闭混杂模式
if os.name == "nt":
sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
运行结果:
SocketServer
这个类主要是为了简化网络服务器的开发而实现的。它有4个基本的服务器类。
- SocketServer.TCPServer
用于TCP协议,提供Client与Server通信。 - SocketServer.UDPServer
用于UDP传输,一种基于UPD的网络报文通信。 - SocketServer.UnixStreamServer
- SocketServer.UnixDatagramServer
这两个类用得比较少,与前面TCP、UDP类用法相似。但这两个类只能用在Unix或类Unix系统上。
下面是这4个类的继承与相联关系
+————+
| BaseServer |
+————+
|
v
+———–+ +——————+
| TCPServer |——->| UnixStreamServer |
+———–+ +——————+
|
v
+———–+ +——————–+
| UDPServer |——->| UnixDatagramServer |
+———–+ +——————–+
创建一个Server,通常需要几个步骤:
- 创建处理client端请求的BaseRequestHandler子类,并重写handl()方法。在这个方法里面,用于处理client端的请求;
- 用服务器地址与端口和BaseRequestHandler子类作为参数实例化一个Serversocket对象
- 调用server_close()关闭Serversocket。
Demo for SocketServer.TCPServer
Server端
import SocketServer
class MyTCPHandler(SocketServer.BaseRequestHandler):
#重载handle(),用于处理client端的request
def handle(self):
# self.request是连接cerver端的client socket
self.data = self.request.recv(1024).strip()
print "{} wrote:".format(self.client_address[0])
print self.data
self.request.sendall(self.data.upper())
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
# 实例化TCPServer
server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
Client端
import socket
import sys
HOST, PORT = "localhost", 9999
data = " ".join(sys.argv[1:])
# 实例化client socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
# connect服务端并发送数据
sock.connect((HOST, PORT))
sock.sendall(data + "\n")
received = sock.recv(1024)
finally:
sock.close()
print "Sent: {}".format(data)
print "Received: {}".format(received)
运行结果:
Demo for SocketServer.UDPServer
Server端
import SocketServer
class MyUDPHandler(SocketServer.BaseRequestHandler):
#重载handle()用于处理client request
def handle(self):
data = self.request[0].strip()
socket = self.request[1]
print "{} wrote:".format(self.client_address[0])
print data
socket.sendto(data.upper(), self.client_address)
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
#实例化UDPServer
server = SocketServer.UDPServer((HOST, PORT), MyUDPHandler)
server.serve_forever()
Client端:
import socket
import sys
HOST, PORT = "localhost", 9999
data = " ".join(sys.argv[1:])
# 实例化UDP client socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#连接Server端并发送数据
sock.sendto(data + "\n", (HOST, PORT))
received = sock.recv(1024)
print "Sent: {}".format(data)
print "Received: {}".format(received)
运行结果:
参考链接:
菜鸟笔记:http://www.runoob.com/python/python-socket.html
Python类库文档:http://python.usyiyi.cn/