python網(wǎng)絡(luò)編程學(xué)習(xí)筆記(三):socket網(wǎng)絡(luò)服務(wù)器
1、TCP連接的建立方法
客戶端在建立一個(gè)TCP連接時(shí)一般需要兩步,而服務(wù)器的這個(gè)過程需要四步,具體見下面的比較。
| 步驟 | TCP客戶端 | TCP服務(wù)器 |
| 第一步 | 建立socket對(duì)象 | 建立socket對(duì)象 |
| 第二步 | 調(diào)用connect()建立一個(gè)和服務(wù)器的連接 | 設(shè)置socket選項(xiàng)(可選) |
| 第三步 | 無 | 綁定到一個(gè)端口(也可以是一個(gè)指定的網(wǎng)卡) |
| 第四步 | 無 | 偵聽連接 |
下面具體來講這四步的建立方法:
第一步,建立socket對(duì)象:這里與客戶端一樣,依然是:
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
第二步,設(shè)置和得到socket選項(xiàng)
python定義了setsockopt()和getsockopt(),一個(gè)是設(shè)置選項(xiàng),一個(gè)是得到設(shè)置。這里主要使用setsockopt(),具體結(jié)構(gòu)如下:
setsockopt(level,optname,value)
level定義了哪個(gè)選項(xiàng)將被使用。通常情況下是SOL_SOCKET,意思是正在使用的socket選項(xiàng)。它還可以通過設(shè)置一個(gè)特殊協(xié)議號(hào)碼來設(shè)置協(xié)議選項(xiàng),然而對(duì)于一個(gè)給定的操作系統(tǒng),大多數(shù)協(xié)議選項(xiàng)都是明確的,所以為了簡(jiǎn)便,它們很少用于為移動(dòng)設(shè)備設(shè)計(jì)的應(yīng)用程序。
optname參數(shù)提供使用的特殊選項(xiàng)。關(guān)于可用選項(xiàng)的設(shè)置,會(huì)因?yàn)椴僮飨到y(tǒng)的不同而有少許不同。如果level選定了SOL_SOCKET,那么一些常用的選項(xiàng)見下表:
|
選項(xiàng) |
意義 |
期望值 |
|
SO_BINDTODEVICE |
可以使socket只在某個(gè)特殊的網(wǎng)絡(luò)接口(網(wǎng)卡)有效。也許不能是移動(dòng)便攜設(shè)備 |
一個(gè)字符串給出設(shè)備的名稱或者一個(gè)空字符串返回默認(rèn)值 |
|
SO_BROADCAST |
允許廣播地址發(fā)送和接收信息包。只對(duì)UDP有效。如何發(fā)送和接收廣播信息包 |
布爾型整數(shù) |
|
SO_DONTROUTE |
禁止通過路由器和網(wǎng)關(guān)往外發(fā)送信息包。這主要是為了安全而用在以太網(wǎng)上UDP通信的一種方法。不管目的地址使用什么IP地址,都可以防止數(shù)據(jù)離開本地網(wǎng)絡(luò) |
布爾型整數(shù) |
|
SO_KEEPALIVE |
可以使TCP通信的信息包保持連續(xù)性。這些信息包可以在沒有信息傳輸?shù)臅r(shí)候,使通信的雙方確定連接是保持的 |
布爾型整數(shù) |
|
SO_OOBINLINE |
可以把收到的不正常數(shù)據(jù)看成是正常的數(shù)據(jù),也就是說會(huì)通過一個(gè)標(biāo)準(zhǔn)的對(duì)recv()的調(diào)用來接收這些數(shù)據(jù) |
布爾型整數(shù) |
|
SO_REUSEADDR |
當(dāng)socket關(guān)閉后,本地端用于該socket的端口號(hào)立刻就可以被重用。通常來說,只有經(jīng)過系統(tǒng)定義一段時(shí)間后,才能被重用。 |
布爾型整數(shù) |
本節(jié)在學(xué)習(xí)時(shí),用到了SO_REUSEADDR選項(xiàng),具體寫法是:
S.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 這里value設(shè)置為1,表示將SO_REUSEADDR標(biāo)記為TRUE,操作系統(tǒng)會(huì)在服務(wù)器socket被關(guān)閉或服務(wù)器進(jìn)程終止后馬上釋放該服務(wù)器的端口,否則操作系統(tǒng)會(huì)保留幾分鐘該端口。
下面的方法可以幫助給出該系統(tǒng)下python所支持的socket選項(xiàng)列表:
import socket
solist=[x for x in dir(socket) if x.startswith('SO_')]
solist.sort()
for x in solist:
Print x
第三步:綁定socket
綁定即為服務(wù)器要求一個(gè)端口號(hào)。
S.bind((host,port)),其中host為服務(wù)器ip,通常為空,也可以綁定到一個(gè)特定的ip地址。Port為端口號(hào)。
第四步:偵聽連接。
利用listen()函數(shù)進(jìn)行偵聽連接。該函數(shù)只有一個(gè)參數(shù),其指明了在服務(wù)器實(shí)際處理連接的時(shí)候,允許有多少個(gè)未決(等待)的連接在隊(duì)列中等待。作為一個(gè)約定,很多人設(shè)置為5。如:s.listen(5)
2、簡(jiǎn)單的TCP服務(wù)器實(shí)例
這個(gè)建立一個(gè)簡(jiǎn)單的TCP服務(wù)器和客戶端。
服務(wù)器端:TCP響應(yīng)服務(wù)器,當(dāng)與客戶端建立連接后,服務(wù)器顯示客戶端ip和端口,同時(shí)將接收的客戶端信息和'I get it!'傳給客戶端,此時(shí)等待輸入一個(gè)新的信息傳給客戶端。
客戶端:TCP客戶端,首先輸入服務(wù)器ip地址,然后輸入信息,回車后會(huì)得到服務(wù)器返回信息,然后等待服務(wù)器向其發(fā)送信息后退出。
具體代碼如下:
服務(wù)器端:tcpserver.py
# -*- coding: cp936 -*-
##tcp響應(yīng)服務(wù)器,當(dāng)與客戶端建立連接后,服務(wù)器顯示客戶端ip和端口,同時(shí)將接收的客戶端信息和'I get it!'傳給客戶端,此時(shí)等待輸入一個(gè)新的信息傳給客戶端。
##@小五義
import socket,traceback
host=''
port=12345
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
s.bind((host,port))
s.listen(1)
while 1:
try:
clientsock,clientaddr=s.accept()
except KeyboardInterrupt:
raise
except:
traceback.print_exc()
continue
try:
print "連接來自:",clientsock.getpeername()
while 1:
data=clientsock.recv(4096)
if not len(data):
break
print clientsock.getpeername()[0]+':'+str(data)
clientsock.sendall(data)
clientsock.sendall("\nI get it!\n")
t=raw_input('input the word:')
clientsock.sendall(t)
except (KeyboardInterrupt,SystemExit):
raise
except:
traceback.print_exc()
try:
clientsock.close()
except KeyboardInterrupt:
raise
except:
traceback.print_exc()
客戶端:tcpclient.py
# -*- coding: cp936 -*-
##tcp客戶端,首先輸入服務(wù)器ip地址,然后輸入信息,回車后會(huì)得到服務(wù)器返回信息,然后等待服務(wù)器向其發(fā)送信息后退出。
##@小五義
import socket,sys
port=12345
host=raw_input('輸入服務(wù)器ip:')
data=raw_input('輸入要發(fā)送的信息:')
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
try:
s.connect((host,port))
except:
print '連接錯(cuò)誤!'
s.send(data)
s.shutdown(1)
print '發(fā)送完成。'
while 1:
buf=s.recv(4096)
if not len(buf):
break
sys.stdout.write(buf)
執(zhí)行結(jié)果:
客戶端輸入hello,服務(wù)器端輸入ok,具體顯示結(jié)果是:
服務(wù)器端:
連接來自:('127.0.0.1',1945)
127.0.0.1:hello
Input the world:ok
客戶端:
輸入服務(wù)器ip:127.0.0.1
輸入要發(fā)送的信息:hello
發(fā)送完成。
hello
I get it!
ok
3、UDP服務(wù)器
UDP服務(wù)器建立與TCP相類似,具體比較如下:
|
步驟 |
UDP |
TCP |
|
第一步 |
建立socket對(duì)象 |
建立socket對(duì)象 |
|
第二步 |
設(shè)置socket選項(xiàng) |
設(shè)置socket選項(xiàng) |
|
第三步 |
綁定到一個(gè)端口 |
綁定到一個(gè)端口 |
|
第四步 |
Recvfrom() |
偵聽連接listen |
這里利用UDP建立一個(gè)時(shí)間服務(wù)器。
代碼如下:
服務(wù)器端;serverudp.py
# -*- coding: cp936 -*-
##UDP服務(wù)器端,客戶端連接后,向其發(fā)送當(dāng)前時(shí)間
##@小五義
import socket,traceback,time,struct
host=''
port=12345
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
s.bind((host,port))
while 1:
try:
message,address=s.recvfrom(8192)
secs=int(time.time())
reply=struct.pack("!I",secs)
s.sendto(reply,address)
except (KeyboardInterrupt,SystemExit):
raise
except:
traceback.print_exc()
客戶端:clientudp.py
# -*- coding: cp936 -*-
##udp客戶端,向服務(wù)器發(fā)送一個(gè)空字符后,得到服務(wù)器返回時(shí)間
##@小五義
import socket,sys,struct,time
host=raw_input('輸入服務(wù)器地址:')
port=12345
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.sendto('',(host,port))
print "等待回復(fù)……"
buf=s.recvfrom(2048)[0]
if len(buf)!=4:
print "回復(fù)錯(cuò)誤%d:%s"%(len(buf),buf)
sys.exit(1)
secs=struct.unpack("!I",buf)[0]
print time.ctime(int(secs))
運(yùn)行結(jié)果:
首先運(yùn)行服務(wù)器端,然后運(yùn)行客戶端。
C:\>python clientudp.py ##clientudp.py程序存放在在c盤下
輸入服務(wù)器地址:127.0.0.1
等待回復(fù)……
Mon Aug 06 17:09:17 2012
- python使用socket連接遠(yuǎn)程服務(wù)器的方法
- Python socket處理client連接過程解析
- python實(shí)現(xiàn)socket+threading處理多連接的方法
- python通過socket實(shí)現(xiàn)多個(gè)連接并實(shí)現(xiàn)ssh功能詳解
- python使用socket遠(yuǎn)程連接錯(cuò)誤處理方法
- python使用socket進(jìn)行簡(jiǎn)單網(wǎng)絡(luò)連接的方法
- Python 網(wǎng)絡(luò)編程起步(Socket發(fā)送消息)
- Python采用socket模擬TCP通訊的實(shí)現(xiàn)方法
- python實(shí)現(xiàn)socket客戶端和服務(wù)端簡(jiǎn)單示例
- Python Socket實(shí)現(xiàn)簡(jiǎn)單TCP Server/client功能示例
- python使用socket向客戶端發(fā)送數(shù)據(jù)的方法
- Python socket連接中的粘包、精確傳輸問題實(shí)例分析
相關(guān)文章
Python隨機(jī)數(shù)random模塊使用指南
本文給大家分享的是Python隨機(jī)數(shù)random模塊的幾個(gè)常用的方法,非常的簡(jiǎn)單,小伙伴們喜歡的話,后續(xù)繼續(xù)深入探討2016-09-09
python 編程之twisted詳解及簡(jiǎn)單實(shí)例
這篇文章主要介紹了python 編程之twisted詳解及簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-01-01
django的聚合函數(shù)和aggregate、annotate方法使用詳解
這篇文章主要介紹了django的聚合函數(shù)和aggregate、annotate方法使用詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07
如何在django里上傳csv文件并進(jìn)行入庫處理的方法
這篇文章主要介紹了如何在django里上傳csv文件并進(jìn)行入庫處理的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-01-01
詳解Django+uwsgi+Nginx上線最佳實(shí)戰(zhàn)
這篇文章主要介紹了Django+uwsgi+Nginx上線最佳實(shí)戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03
Python?GUI利用tkinter皮膚ttkbootstrap實(shí)現(xiàn)好看的窗口
這篇文章主要介紹了Python?GUI利用tkinter皮膚ttkbootstrap實(shí)現(xiàn)好看的窗口,文章基于python的相關(guān)資料展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下2022-06-06

