编程开发 购物 网址 游戏 小说 歌词 地图 快照 股票 美女 新闻 笑话 | 汉字 软件 日历 阅读 下载 图书馆 开发 租车 短信 China
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
移动开发 架构设计 编程语言 互联网 开发经验 Web前端 开发总结
开发杂谈 系统运维 研发管理 数据库 云 计 算 Java开发
VC(MFC) Delphi VB C++(C语言) C++ Builder 其它开发语言 云计算 Java开发 .Net开发 IOS开发 Android开发 PHP语言 JavaScript
ASP语言 HTML(CSS) HTML5 Apache MSSQL数据库 Oracle数据库 PowerBuilder Informatica 其它数据库 硬件及嵌入式开发 Linux开发资料
  编程开发知识库 -> 数据库 -> Python黑帽编程2.8 套接字编程 -> 正文阅读
 

[数据库]Python黑帽编程2.8 套接字编程[第1页]




Python黑帽编程2.8 套接字编程


套接字编程在本系列教程中地位并不是很突出,但是我们观察网络应用,绝大多数都是基于Socket来做的,哪怕是绝大多数的木马程序也是如此。官方关于socket编程的文档地址为https://docs.python.org/2/library/socket.html,我承认我看起来都很费劲。
套接字为BSD UNIX系统核心的一部分,而且他们也被许多其他类似UNIX的操作系统包括Linux所采纳。许多非BSD UNIX系统(如ms-dos,windows,os/2,mac os及大部分主机环境)都以库形式提供对套接字的支持。
三种最流行的套接字类型是:stream,datagram和raw。stream和datagram套接字可以直接与TCP协议进行接口,而raw套接字则接口到IP协议。但套接字并不限于TCP/IP。
Python 提供了两个基本的套接字模块:
l  第一个是 socket,它提供了标准的 BSD Sockets API。
l  第二个是 socketServer, 它提供了服务器中心类,可以简化网络服务器的开发。
本节课程主要关注socket模块的使用。

2.8.1 SOCKET函数


socket函数用来创建socket对象,使用前需要导入socket模块。我们先看一下socket函数的使用方式:
socket.socket([family[, type[, proto>)
我们看到socket函数接收三个参数,下面分别介绍:
family——套接字对象使用的地址族,可选值:AF_INET——IPv4地址族,AF_INET6——IPv6地址族,AF_UNIX——针对类UNIX系统的套接字,如图2所示。

图2
type可选参数如图3所示。

图3
proto是协议数,默认是0,通常不需要关心该参数。
熟悉了三个参数的含义,创建一个TCP或者UDP的socket对象就很容易了。
创建TCP Socket:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
创建UDP Socket:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
关于socket对象的各种方法的使用说明,大家可以去查官方文档,我这里就不贴了,下面我们边实践,边学习。

2.8.2 创建SOCKET


我们首先来创建一个TCP的socket对象,代码如下:
#Socket client example in python
import socket   #for sockets
 
#create an AF_INET, STREAM socket (TCP)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket Created'
创建一个socket对象很简单,第一步导入socket模块,第二步使用socket.socket方法创建一个socket对象,参数在2.8.1节已经做了说明。运行结果如下:

图4

2.8.3 客户端编程


创建socket之后,现在我们看看如何创建client端,连接一个服务端,这里我们选择知乎(www.zhihu.com)。socket类有个gethostbyname方法,可以用来把域名转换为ip地址,例如:
import socket   #for sockets
import sys  #for exit
 
try:
    #create an AF_INET, STREAM socket (TCP)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
    print 'Failed to create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
    sys.exit();
 
print 'Socket Created'
 
host = 'www.zhihu.com'
 
try:
    remote_ip = socket.gethostbyname( host )
except socket.gaierror:
    #could not resolve
    print 'Hostname could not be resolved. Exiting'
    sys.exit()
    
print 'Ip address of ' + host + ' is ' + remote_ip
上面的代码,我们首先导入了sys模块,用于在出现异常的情况下调用sys.exit()退出。同时,完善了异常捕获,创建socket可能会引发socket.error异常,gethostbyname方法可能会引发socket.gaierror异常,我们在编程过程中要注意这些错误。
运行结果如下:

图5
现在我们获得了ip,端口我们使用80,现在可以连接服务器了。
import socket   #for sockets
import sys  #for exit
 
try:
    #create an AF_INET, STREAM socket (TCP)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
    print 'Failed to create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
    sys.exit();
 
print 'Socket Created'
 
host = 'www.zhihu.com'
port = 80
 
try:
    remote_ip = socket.gethostbyname( host )
 
except socket.gaierror:
    #could not resolve
    print 'Hostname could not be resolved. Exiting'
    sys.exit()
    
print 'Ip address of ' + host + ' is ' + remote_ip
 
#Connect to remote server
s.connect((remote_ip , port))
 
print 'Socket Connected to ' + host + ' on ip ' + remote_ip
注意上面加粗的代码,使用socket.connect方法连接服务端,参数为ip地址和端口。
连接上服务器之后,现在可以向服务器发送信息了。
我们在上面代码的基础上,添加下面的代码:
#Send some data to remote server
message = "GET / HTTP/1.1\r\n\r\n"
 
try :
    #Set the whole string
    s.sendall(message)
except socket.error:
    #Send failed
    print 'Send failed'
    sys.exit()
 
print 'Message send successfully'
首先定义了要发送的信息,准备发送一个http协议的get请求。随后我们使用socket.sendall方法发送信息。信息发送之后,如果没有异常产生,应该会得到知乎服务器的响应内容。那么如何接收信息呢?继续添加如下代码:
#Now receive data
reply = s.recv(4096)
 
print reply
我们使用socket.recv方法来接收数据,参数是接收的数据长度。现在我们来看一下运行结果:

图6
最后,接收完数据之后,不要忘了关闭socket:
s.close()
现在我们来总结下客户端socket编程的基本流程:
1.      创建套接字
2.      连接服务端
3.      发送数据
4.      接收数据
5.      关闭连接
下面看一下,一个基本的服务端,要做哪些工作。

2.8.4 服务端编程


和客户端编程类似,我们首先创建一个socket对象。
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
随后,我们要把socket绑定到本机的IP和端口上。
try:
    s.bind((HOST, PORT))
except socket.error , msg:
    print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
绑定ip和端口使用的是bind方法。
服务端不会主动连接其他主机,而是等待客户端连接,这需要进入监听状态。
s.listen(10)
print 'Socket now listening'
listen方法接收一个参数,用来指定可以同时挂起的连接数。
监听模式之后,如果有客户端连接进来,如何接收连接呢?需要使用accept方法。
#wait to accept a connection - blocking call
conn, addr =s.accept()
accept方法会返回一个代表当前链接的connection对象和客户端的ip地址。接下来就可以使用conn对象来接收和发送数据了,关闭连接也使用conn对象。
data = conn.recv(1024)
conn.sendall(data)
 
conn.close()
下面我们看一下服务端的完整代码:
import socket
import sys
 
HOST = ''   # Symbolic name meaning all available interfaces
PORT = 8888 # Arbitrary non-privileged port
 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
 
try:
    s.bind((HOST, PORT))
except socket.error , msg:
    print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
    sys.exit()
    
print 'Socket bind complete'
 
s.listen(10)
print 'Socket now listening'
#wait to accept a connection - blocking call
conn, addr = s.accept()
print 'Connected with ' + addr[0] + ':' + str(addr[1])
 
#now keep talking with the client
data = conn.recv(1024)
conn.sendall(data)
 
conn.close()
s.close()
将代码保存为socket_server.py,从终端启动,如下图:

图7
然后再启动一个终端,使用telnet连接。

图8
此时可以看到服务端打印了连接的客户端,接下来咋telnet终端输入字符,回车发送过去。结果如图7。

图9
从图7可以看到telnet终端显示了服务端返回的信息。

2.8.5 改进服务端


作为服务端,只能接收一次连接,和客户端进行有限次数的交互是不行的,要一直能接收来自客户端的连接,下面我们改进服务端。
import socket
import sys
 
HOST = ''   # Symbolic name meaning all available interfaces
PORT = 5000 # Arbitrary non-privileged port
 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
 
try:
    s.bind((HOST, PORT))
except socket.error , msg:
    print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
    sys.exit()
    
print 'Socket bind complete'
 
s.listen(10)
print 'Socket now listening'
 
#now keep talking with the client
while 1:
    #wait to accept a connection - blocking call
    conn, addr = s.accept()
    print 'Connected with ' + addr[0] + ':' + str(addr[1])
    
    data = conn.recv(1024)
    reply = 'OK...' + data
    if not data:
        break
    
    conn.sendall(reply)
 
conn.close()
s.close()
修改后的代码只是将接收客户端连接的代码放到一个while true循环里,这样就可以不停的接收连接。保存上面的代码,在终端打开等待连接,然后启动三个终端使用telnet进行连接,结果如下:

图10
这样改起来,可以不停的接收新的连接了,但是每次只能接收一个连接,有新连接的时候,旧连接就会断掉,还是不够完美。想要分别对待每一个新入的连接,需要多线程登场了。
import socket
import sys
from thread import *
 
HOST = ''   # Symbolic name meaning all available interfaces
PORT = 8888 # Arbitrary non-privileged port
 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
 
#Bind socket to local host and port
try:
    s.bind((HOST, PORT))
except socket.error , msg:
    print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
    sys.exit()
    
print 'Socket bind complete'
 
#Start listening on socket
s.listen(10)
print 'Socket now listening'
 
#Function for handling connections. This will be used to create threads
def clientthread(conn):
    #Sending message to connected client
    conn.send('Welcome to the server. Type something and hit enter\n') #send only takes string
    
    #infinite loop so that function do not terminate and thread do not end.
    while True:
        
        #Receiving from client
        data = conn.recv(1024)
        reply = 'OK...' + data
        if not data:
            break
    
        conn.sendall(reply)
    
    #came out of loop
    conn.close()
 
#now keep talking with the client
while 1:
    #wait to accept a connection - blocking call
    conn, addr = s.accept()
    print 'Connected with ' + addr[0] + ':' + str(addr[1])
    
    #start new thread takes 1st argument as a function name to be run, second is the tuple of arguments to the function.
    start_new_thread(clientthread ,(conn,))
 
s.close()
使用多线程,首先要导入thread模块。随后我们定义了一个名为clientthread的方法,该方法接收每个客户端连接对象,在内部启动一个新的while循环,这样可以保证客户端和服务端可以一直连接,反复通信。在外层,仍然保留while循环,每次有客户端连接的时候,生成一个连接对象conn,然后使用thread模块的start_new_thread方法启动一个新的线程,新线程调用clientthread方法,传入刚接收的客户端连接对象。
我们将上面的代码保存为socket_thread.py,然后从终端启动,在启动多个终端使用telnet进行连接,连接之后发消息测试,结果如下:

图11

2.8.6 小结


本节我们学习了Python中socket的基本使用方法,并演示了基于TCP协议的客户端和服务端编程方法。这里大家需要额外补充的知识点是多线程的使用,我们做网络扫描、爬虫等程序,都是离不开多线程应用的。
 
下一节是第二章的最后一节,和大家聊一聊面向对象编程思想及Python的面向对象编程方法。
第2.9节《面向对象编程思想及Python的面向对象编程方法》已经在微信订阅号抢先发布,心急的同学进入订阅号(二维码在下方),从菜单“网络安全”—>”Python黑帽编程”进入即可。
 
查看完整系列教程,请关注我的微信订阅号(xuanhun521,下方二维码),回复“python”。问题讨论请加qq群:Hacking (1群):303242737   Hacking (2群):147098303。
 

  数据库 最新文章
Oracle之复杂查询
数据仓库学习笔记一
SQL语句
17.Oracle杂记——数据字典dba_ts_quotas
18.Oracle杂记——数据字典dba_users
19.Oracle杂记——数据字典dba_views
MySQL分区表
实现一个Android锁屏App的难点总结
mysql用root登录,执行revoke all privileg
innodb 引擎相关模块
上一篇文章      下一篇文章      查看所有文章
加:2016-08-17 21:36:20  更:2016-08-17 21:41:32 
VC(MFC) Delphi VB C++(C语言) C++ Builder 其它开发语言 云计算 Java开发 .Net开发 IOS开发 Android开发 PHP语言 JavaScript
ASP语言 HTML(CSS) HTML5 Apache MSSQL数据库 Oracle数据库 PowerBuilder Informatica 其它数据库 硬件及嵌入式开发 Linux开发资料
360图书馆 软件开发资料 文字转语音 购物精选 软件下载 美食菜谱 新闻资讯 电影视频 小游戏 Chinese Culture 股票 租车
生肖星座 三丰软件 视频 开发 短信 中国文化 网文精选 搜图网 美图 阅读网 多播 租车 短信 看图 日历 万年历 2018年2日历
2018-2-26 1:29:26
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  编程开发知识库