上一篇笔记的补充:
为了验证 socket 状态的问题,可以在主机操作系统和 VMware kali 客户机系统运行TCP 服务端和客户端程序,通过查看两个主机的网络连接来进行理解。
我在主机操作系统(Win7)用 phpstudy 搭建了 Web 站点,客户机通过浏览器或 netcat 连接服务端。分别在两台机器上用 netstat 查看 TCP 连接。注意的是,VMware 网卡要使用桥接模式,这样主机系统和客户机系统才能在同一个网段里相互访问,用 netstat 查看的连接是两个系统直连的结果。
Windows 用 netstat -bno -p TCP |find ":80"
Kali 用 netstat -nva --tcp
C:\Users\Administrator
λ netstat -bno -p TCP |find ":80"
TCP 192.168.1.3:80 192.168.1.111:45722 ESTABLISHED 7760
root@kali:~# netstat -nva --tcp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 192.168.1.111:45716 192.168.1.3:80 TIME_WAIT
步骤:
socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((target_host, target_port))
client.send()
client.recv()
client.close()
Python2 代码:
import socket
target_host = "www.baidu.com"
target_port = 80
# create a socket object
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# connect the client
client.connect((target_host, target_port))
# send some data
client.send("GET / HTTP/1.1\r\nHost:baidu.com\r\n\r\n")
# receive data
response = client.recv(4096)
print response
在 Python3 下,运行上述代码,调用 socket.send
出现 TypeError: a bytes-like object is required, not 'str'
错误。
(venv-p3) root@kali:~/Black-Hat-Python/codes# python tcp-client.py
Traceback (most recent call last):
File "tcp-client.py", line 10, in <module>
client.send("GET / HTTP/1.1\r\nHOST:baidu.com\r\n\r\n")
TypeError: a bytes-like object is required, not 'str'
因为 python2 和 python3 版本差异,python3 对文本和二进制数据做了更清晰的区分。文本用 unicode 编码,为 str 类型,二进制数据则为 bytes 类型。
python有两种类型转换的函数 encode(), decode()
* encode(编码),可以将 str 类型编码为 bytes 。
* decode(译码),可以将 bytes 类型转换为 str 类型。
这里的错误是因为要求 bytes 类型却给了 str 类型,send() 函数是传输字节流。解决方法:
用 str.encode()
和 bytes.decode()
函数
request_heads = "GET / HTTP/1.1\r\nHOST:192.168.1.3\r\n\r\n"
client.send(str.encode(request_heads))
print(bytes.decode(response))
或者在字符串前加上 b
b"GET / HTTP/1.1\r\nHOST:192.168.1.3\r\n\r\n"
修改的 Python3 代码:
#!/usr/bin/env python3
# -*- code: utf-8 -*-
import socket
target_host = "192.168.1.3"
target_port = 80
# create a socket object
# AF_INET means IPv4 address, socket.SOCK_STREAM means TCP protocol
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# connect the server
# param is a tuple, (host, port)
client.connect((target_host, target_port))
# send HTTP request head with GET model
# encode str type to byte type
request_heads = "GET / HTTP/1.1\r\nHOST:192.168.1.3\r\n\r\n"
client.send(str.encode(request_heads))
# receive datas
response = client.recv(4096)
# decode byte type to str type
print(bytes.decode(response))
# close the socket
client.close()
运行结果:
(venv-p3) root@kali:~/Black-Hat-Python/codes# python tcp-client.py
HTTP/1.1 200 OK
Date: Tue, 20 Mar 2018 16:02:11 GMT
Server: Apache/2.4.23 (Win32) OpenSSL/1.0.2j PHP/5.2.17
X-Powered-By: PHP/5.2.17
Content-Length: 12
Content-Type: text/html
Hello World
步骤:
socket.socket(socket.AF_INET, socket.SOCK_STREAM)
bind((bing_ip, bind_ports))
listen(5)
accept()
Python2 代码:
import socket
import threading
bind_ip = "0.0.0.0"
bind_port = 9999
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((bind_ip, bind_port))
server.listen(5)
print "[*] Listening on %s:%d" % (bind_ip, bind_port)
def handle_client(client_socket):
# send something
client_socket.send("Connected\r\n")
# print out what the client sends
request = client_socket.recv(1024)
print "[*] Reveived: %s" % request
# send back a packet
client_socket.send("ACK!\r\n")
client_socket.close()
while True:
client, addr = server.accept()
print "[*] Accepted connection from: %s:%d" % (addr[0], addr[1])
# spin up our client thread to handle incoming data
client_handler = threading.Thread(target=handle_client,args=(client,))
client_handler.start()
Python3 代码:
#!/usr/bin/env python3
# -*- code: utf-8 -*-
import socket
import threading
bind_ip = "0.0.0.0" # all ip
bind_port = 9999 # greater than 1024 is better
# create socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind ip and port
server.bind((bind_ip, bind_port))
# start listen, max socket nums 5
server.listen(5)
print("[*] Listening on %s:%d"%(bind_ip, bind_port))
def handle_client(client_socket):
request = client_socket.recv(1024)
print("[*] Received: %s" % request)
client_socket.send(b"ACK!\r\n")
client_socket.close()
while True:
# accept a client connection.
client,addr = server.accept()
print("[*] Accepted connection from: %s:%d" % (addr[0], addr[1]))
# create a thread to handle incoming connection.
client_handler = threading.Thread(target=handle_client, args=(client,))
# start the thread.
client_handler.start()
运行结果,服务端:
root@kali:~# cd Black-Hat-Python/
root@kali:~/Black-Hat-Python# source venv-p3/bin/activate
(venv-p3) root@kali:~/Black-Hat-Python# cd codes/
(venv-p3) root@kali:~/Black-Hat-Python/codes# ls
tcp-client.py tcp-server.py test.py
(venv-p3) root@kali:~/Black-Hat-Python/codes# python tcp-server.py
[*] Listening on 0.0.0.0:9999
[*] Accepted connection from: 127.0.0.1:50512
[*] Received: b'aaaa\n'
用 nc 连接:
root@kali:~# nc 127.0.0.1 9999
aaaa
ACK!
UDP 协议和 TCP 协议不同的是,UDP 是面向非连接的,不需要和服务端先建立连接,直接可以和服务端进行数据传输。
客户端 Python2 代码:
import socket
target_host = "127.0.0.1"
target_port = 80
# create a socket object
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# send some data
client.sendto("AAABBBCCC",(target_host, target_port))
# recieve some data
data, addr = client.recvfrom(4096)
print data
客户端 Python3 代码:
import socket
target_host = "127.0.0.1"
target_port = 9998
# create a socket object
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# send some data
client.sendto(b"AAABBBCCC",(target_host, target_port))
# recieve some data
data, addr = client.recvfrom(4096)
print data
服务端 Python3 代码:
#!/usr/bin/env python3
# -*- code: utf-8 -*-
import socket
import threading
bind_ip = "0.0.0.0" # all ip
bind_port = 9998 # greater than 1024 is better
# create socket
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# bind ip and port
server.bind((bind_ip, bind_port))
print("[*] Binding on %s:%d" % (bind_ip, bind_port))
while True:
# receive datas:
data, addr = server.recvfrom(1024)
print('Received from %s:%s: %s.' % (addr[0],addr[1], data))
server.sendto(b'Hello, %s!' % data, addr)
运行结果,服务端:
(venv-p3) root@kali:~/Black-Hat-Python/codes# python udp-server.py
[*] Binding on 0.0.0.0:9998
Received from 127.0.0.1:60558: b'AAABBBCCC'.
Received from 127.0.0.1:45700: b'AAABBBCCC'.
客户端:
root@kali:~/Black-Hat-Python/codes# python udp-client.py
Hello, AAABBBCCC!