socket收包,如前面的文章实现了python socket发ping包,并且收到了对端的返回结果,那么如何把返回的包也用socket收上来呢?疑问,socket建立了一个管道,管道建好以后可以通过管道把包发出去,怎么保证收到的包也可以从管道上来呢?答案:socket只要建立好之后,就有发包和收包两种方法。直接使用 socket.recv方法就可以。但是 recv方法一次只能收一个包,和sendto方法一次只能发送一个包的道理类似。收上来的包如果不做类型转化默认为 str类型,需要转化为bytearray类型,才能通过ICMP协议规定的组织结构,通过字节偏移取出各个字段。
另外:如果要写连续ping 多个不同的ip地址,并且收包完成的话,需要设计总的超时时间。这个在下一节中在实现。
recv,解包代码如下:
源码如下:
#!/bin/env/python
import socket
import struct
import os
import time
_ICMP_HDR_OFFSET =20
_ICMP_ECHO_REPLY =0
_ICMP_ID_OFFSET = _ICMP_HDR_OFFSET +4
_ICMP_IDENT_OFFSET = _ICMP_HDR_OFFSET +6
_ICMP_PAYLOAD_OFFSET = _ICMP_HDR_OFFSET +8
# create icmp socket
def create_socket():
proto ='ICMP'
try:
icmp_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
print icmp_socket
except Exception as e:
raise e
return icmp_socket
def checksum(source_string):
"""
I'm not too confident that this is right but testing seems
to suggest that it gives the same answers as in_cksum in ping.c
"""
sum =0
countTo = (len(source_string)/2)*2
count =0
while count
thisVal =ord(source_string[count +1])*256 +ord(source_string[count])
sum = sum + thisVal
sum = sum &0xffffffff # Necessary?
count = count +2
if countTo
sum = sum +ord(source_string[len(source_string) -1])
sum = sum &0xffffffff # Necessary?
sum = (sum >>16) + (sum &0xffff)
sum = sum + (sum >>16)
answer = ~sum
answer = answer &0xffff
# Swap bytes. Bugger me if I know why.
answer = answer >>8 | (answer <<8 &0xff00)
return answer
# generate icmp data
def generate_pkg():
## ICMP pkg header
pkt_id = os.getpid()
ident =0
pkg_header_pre = struct.pack("!BBHHH",8,0,0, pkt_id, ident)
payload = struct.pack("d", time.time())
pkgheader_check = checksum(pkg_header_pre+payload)
pkg_header = struct.pack("!BBHHH",8,0, pkgheader_check, pkt_id, ident)
pkg = pkg_header+payload
return pkg
def send_pkg(icmp_socket,pkt,dst_addr):
icmp_socket.sendto(pkt,dst_addr)
def recrive_pkg(icmp_socket):
pkts = []
icmp_socket.settimeout(100)
p = icmp_socket.recv(64)
print type(p)
pkt =bytearray(p)
print type(pkt)
pkts.append((bytearray(pkt), time.time()))
print pkts
print pkt[_ICMP_HDR_OFFSET]
pkt_id = (pkt[_ICMP_ID_OFFSET] <<8) + pkt[_ICMP_ID_OFFSET +1]
pkt_ident = (pkt[_ICMP_IDENT_OFFSET] <<8) + pkt[_ICMP_IDENT_OFFSET +1]
payload = pkt[_ICMP_PAYLOAD_OFFSET :]
print pkt_id
print pkt_ident
print payload
if __name__ =='__main__':
icmp_socket = create_socket()
pkt = generate_pkg()
dst_addr ='61.135.169.121'
real_dst_addr = (dst_addr,0)
send_pkg(icmp_socket, pkt, real_dst_addr)
recrive_pkg(icmp_socket)