Python黑帽編程2.8 套接字編程

代碼不好排版,可以到微信訂閱號(xuanhun521)查看原文掀抹。

Python黑帽編程2.8套接字編程

套接字編程在本系列教程中地位并不是很突出傲武,但是我們觀察網(wǎng)絡(luò)應(yīng)用城榛,絕大多數(shù)都是基于Socket來做的,哪怕是絕大多數(shù)的木馬程序也是如此疟位。官方關(guān)于socket編程的文檔地址為https://docs.python.org/2/library/socket.html甜刻,我承認(rèn)我看起來都很費勁。

套接字為BSD UNIX系統(tǒng)核心的一部分傻铣,而且他們也被許多其他類似UNIX的操作系統(tǒng)包括Linux所采納祥绞。許多非BSD UNIX系統(tǒng)(如ms-dos蜕径,windows,os/2梦染,mac os及大部分主機(jī)環(huán)境)都以庫形式提供對套接字的支持朴皆。

三種最流行的套接字類型是:stream,datagram和raw。stream和datagram套接字可以直接與TCP協(xié)議進(jìn)行接口渡冻,而raw套接字則接口到IP協(xié)議。但套接字并不限于TCP/IP勋乾。

Python提供了兩個基本的套接字模塊:

l第一個是socket,它提供了標(biāo)準(zhǔn)的BSD Sockets API巍举。

l第二個是socketServer凝垛,它提供了服務(wù)器中心類,可以簡化網(wǎng)絡(luò)服務(wù)器的開發(fā)炭分。

本節(jié)課程主要關(guān)注socket模塊的使用捧毛。

2.8.1 SOCKET函數(shù)

socket函數(shù)用來創(chuàng)建socket對象,使用前需要導(dǎo)入socket模塊师痕。我們先看一下socket函數(shù)的使用方式:

socket.socket([family[, type[, proto]]])

我們看到socket函數(shù)接收三個參數(shù)而账,下面分別介紹:

family——套接字對象使用的地址族福扬,可選值:AF_INET——IPv4地址族惜犀,AF_INET6——IPv6地址族,AF_UNIX——針對類UNIX系統(tǒng)的套接字虽界,如圖2所示莉御。

圖2

type可選參數(shù)如圖3所示礁叔。

圖3

proto是協(xié)議數(shù),默認(rèn)是0煮岁,通常不需要關(guān)心該參數(shù)涣易。

熟悉了三個參數(shù)的含義新症,創(chuàng)建一個TCP或者UDP的socket對象就很容易了。

創(chuàng)建TCP Socket:

sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)

創(chuàng)建UDP Socket:

sock=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

關(guān)于socket對象的各種方法的使用說明荚醒,大家可以去查官方文檔界阁,我這里就不貼了榛瓮,下面我們邊實踐,邊學(xué)習(xí)精续。

2.8.2創(chuàng)建SOCKET

我們首先來創(chuàng)建一個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'

創(chuàng)建一個socket對象很簡單,第一步導(dǎo)入socket模塊弓颈,第二步使用socket.socket方法創(chuàng)建一個socket對象删掀,參數(shù)在2.8.1節(jié)已經(jīng)做了說明披泪。運行結(jié)果如下:

圖4

2.8.3客戶端編程

創(chuàng)建socket之后款票,現(xiàn)在我們看看如何創(chuàng)建client端,連接一個服務(wù)端卡乾,這里我們選擇知乎(www.zhihu.com)缚够。socket類有個gethostbyname方法潮瓶,可以用來把域名轉(zhuǎn)換為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

上面的代碼,我們首先導(dǎo)入了sys模塊思恐,用于在出現(xiàn)異常的情況下調(diào)用sys.exit()退出胀莹。同時,完善了異常捕獲媳否,創(chuàng)建socket可能會引發(fā)socket.error異常篱竭,gethostbyname方法可能會引發(fā)socket.gaierror異常,我們在編程過程中要注意這些錯誤吃媒。

運行結(jié)果如下:

圖5

現(xiàn)在我們獲得了ip赘那,端口我們使用80氯质,現(xiàn)在可以連接服務(wù)器了病梢。

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方法連接服務(wù)端吩蔑,參數(shù)為ip地址和端口烛芬。

連接上服務(wù)器之后,現(xiàn)在可以向服務(wù)器發(fā)送信息了仆潮。

我們在上面代碼的基礎(chǔ)上遣臼,添加下面的代碼:

#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'

首先定義了要發(fā)送的信息揍堰,準(zhǔn)備發(fā)送一個http協(xié)議的get請求。隨后我們使用socket.sendall方法發(fā)送信息隐砸。信息發(fā)送之后季希,如果沒有異常產(chǎn)生,應(yīng)該會得到知乎服務(wù)器的響應(yīng)內(nèi)容武通。那么如何接收信息呢珊搀?繼續(xù)添加如下代碼:

#Now receive data

reply = s.recv(4096)

print reply

我們使用socket.recv方法來接收數(shù)據(jù)境析,參數(shù)是接收的數(shù)據(jù)長度±拖現(xiàn)在我們來看一下運行結(jié)果:

圖6

最后沛鸵,接收完數(shù)據(jù)之后,不要忘了關(guān)閉socket:

s.close()

現(xiàn)在我們來總結(jié)下客戶端socket編程的基本流程:

1.創(chuàng)建套接字

2.連接服務(wù)端

3.發(fā)送數(shù)據(jù)

4.接收數(shù)據(jù)

5.關(guān)閉連接

下面看一下疾捍,一個基本的服務(wù)端栏妖,要做哪些工作吊趾。

2.8.4服務(wù)端編程

和客戶端編程類似,我們首先創(chuàng)建一個socket對象揩尸。

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

隨后岩榆,我們要把socket綁定到本機(jī)的IP和端口上了袁。

try:

s.bind((HOST, PORT))

except socket.error , msg:

print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]

綁定ip和端口使用的是bind方法载绿。

服務(wù)端不會主動連接其他主機(jī),而是等待客戶端連接怀浆,這需要進(jìn)入監(jiān)聽狀態(tài)执赡。

s.listen(10)

print 'Socket now listening'

listen方法接收一個參數(shù),用來指定可以同時掛起的連接數(shù)奠伪。

監(jiān)聽模式之后首懈,如果有客戶端連接進(jìn)來究履,如何接收連接呢最仑?需要使用accept方法。

#wait to accept a connection - blocking call

conn, addr =s.accept()

accept方法會返回一個代表當(dāng)前鏈接的connection對象和客戶端的ip地址欲芹。接下來就可以使用conn對象來接收和發(fā)送數(shù)據(jù)了耀石,關(guān)閉連接也使用conn對象爸黄。

data = conn.recv(1024)

conn.sendall(data)

conn.close()

下面我們看一下服務(wù)端的完整代碼:

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

此時可以看到服務(wù)端打印了連接的客戶端臭觉,接下來咋telnet終端輸入字符,回車發(fā)送過去狞膘。結(jié)果如圖7挽封。

圖9

從圖7可以看到telnet終端顯示了服務(wù)端返回的信息辅愿。

2.8.5改進(jìn)服務(wù)端

作為服務(wù)端,只能接收一次連接鸽素,和客戶端進(jìn)行有限次數(shù)的交互是不行的馍忽,要一直能接收來自客戶端的連接燕差,下面我們改進(jìn)服務(wù)端。

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循環(huán)里,這樣就可以不停的接收連接央串。保存上面的代碼碗啄,在終端打開等待連接稚字,然后啟動三個終端使用telnet進(jìn)行連接,結(jié)果如下:

圖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()

使用多線程歹河,首先要導(dǎo)入thread模塊秸歧。隨后我們定義了一個名為clientthread的方法,該方法接收每個客戶端連接對象谬墙,在內(nèi)部啟動一個新的while循環(huán)拭抬,這樣可以保證客戶端和服務(wù)端可以一直連接弄喘,反復(fù)通信蘑志。在外層贬派,仍然保留while循環(huán)搞乏,每次有客戶端連接的時候请敦,生成一個連接對象conn储玫,然后使用thread模塊的start_new_thread方法啟動一個新的線程撒穷,新線程調(diào)用clientthread方法裆熙,傳入剛接收的客戶端連接對象。

我們將上面的代碼保存為socket_thread.py,然后從終端啟動蛤奥,在啟動多個終端使用telnet進(jìn)行連接凡桥,連接之后發(fā)消息測試缅刽,結(jié)果如下:

圖11

2.8.6小結(jié)

本節(jié)我們學(xué)習(xí)了Python中socket的基本使用方法拷恨,并演示了基于TCP協(xié)議的客戶端和服務(wù)端編程方法谢肾。這里大家需要額外補(bǔ)充的知識點是多線程的使用芦疏,我們做網(wǎng)絡(luò)掃描、爬蟲等程序分预,都是離不開多線程應(yīng)用的。

下一節(jié)是第二章的最后一節(jié)薪捍,和大家聊一聊面向?qū)ο缶幊趟枷爰癙ython的面向?qū)ο缶幊谭椒ā?/p>

2.8節(jié)《面向?qū)ο缶幊趟枷爰癙ython的面向?qū)ο缶幊谭椒?b>》已經(jīng)在微信訂閱號搶先發(fā)布笼痹,心急的同學(xué)進(jìn)入訂閱號(二維碼在下方),從菜單網(wǎng)絡(luò)安全”—>”Python黑帽編程進(jìn)入即可酪穿。

查看完整系列教程凳干,請關(guān)注我的微信訂閱號(xuanhun521,下方二維碼)被济,回復(fù)“python”救赐。問題討論請加qq群:Hacking(1群):303242737?? Hacking(2群):147098303。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末经磅,一起剝皮案震驚了整個濱河市泌绣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌预厌,老刑警劉巖阿迈,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異配乓,居然都是意外死亡仿滔,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門犹芹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來崎页,“玉大人,你說我怎么就攤上這事腰埂§梗” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵屿笼,是天一觀的道長牺荠。 經(jīng)常有香客問我,道長驴一,這世上最難降的妖魔是什么休雌? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮肝断,結(jié)果婚禮上杈曲,老公的妹妹穿的比我還像新娘。我一直安慰自己胸懈,他們只是感情好担扑,可當(dāng)我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著趣钱,像睡著了一般涌献。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上首有,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天燕垃,我揣著相機(jī)與錄音,去河邊找鬼井联。 笑死利术,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的低矮。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼被冒,長吁一口氣:“原來是場噩夢啊……” “哼军掂!你這毒婦竟也來了轮蜕?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤蝗锥,失蹤者是張志新(化名)和其女友劉穎跃洛,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體终议,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡汇竭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了穴张。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片细燎。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖皂甘,靈堂內(nèi)的尸體忽然破棺而出玻驻,到底是詐尸還是另有隱情,我是刑警寧澤偿枕,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布璧瞬,位于F島的核電站,受9級特大地震影響渐夸,放射性物質(zhì)發(fā)生泄漏嗤锉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一墓塌、第九天 我趴在偏房一處隱蔽的房頂上張望瘟忱。 院中可真熱鬧,春花似錦桃纯、人聲如沸酷誓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盐数。三九已至,卻和暖如春伞梯,著一層夾襖步出監(jiān)牢的瞬間玫氢,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工谜诫, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留漾峡,地道東北人。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓喻旷,卻偏偏與公主長得像生逸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容

  • http://python.jobbole.com/85231/ 關(guān)于專業(yè)技能寫完項目接著寫寫一名3年工作經(jīng)驗的J...
    燕京博士閱讀 7,547評論 1 118
  • 最近在學(xué)習(xí)Python看了一篇文章寫得不錯槽袄,是在腳本之家里的烙无,原文如下,很有幫助: 一遍尺、網(wǎng)絡(luò)知識的一些介紹 soc...
    qtruip閱讀 2,688評論 0 6
  • 大綱 一.Socket簡介 二.BSD Socket編程準(zhǔn)備 1.地址 2.端口 3.網(wǎng)絡(luò)字節(jié)序 4.半相關(guān)與全相...
    VD2012閱讀 2,276評論 0 5
  • UIView的常見屬性 NSArray *subviews所有的子控件數(shù)組元素的順序決定著子控件的顯示層級順序(下...
    Jjianshu閱讀 139評論 0 0
  • 等長大了就好了! 等成家了就好了鼓择! 等有孩子就好了三幻! 似乎每進(jìn)入一個人生階段,人就應(yīng)該要長大惯退,隨著肩負(fù)責(zé)任的加大赌髓,...
    東東_ning閱讀 320評論 0 0