socket+網路編程

1.網絡編程shell

經過某種計算機語言來實現不一樣設備間的資源共享和信息傳遞。計算機網絡的創造可能比計算機自己意義更重大!!!(不然,你只能玩單機版遊戲

OSI模型編程

OSI模型定義了不一樣計算機互聯的標準,是設計和描述計算機網絡通訊的基本框架。OSI模型把網絡通訊的工做分爲7層,分別是物理層、數據鏈路層、 網絡層、傳輸層、會話層、表示層和應用層。

網絡通訊的三要素:服務器

A:IP地址   (1) 用來標識網絡上一臺獨立的主機
                   (2) IP地址 = 網絡地址 + 主機地址(網絡號:用於識別主機所在的網絡/網段。主機號:用於識別該網絡中的主機)
                   (3) 特殊的IP地址:127.0.0.1(本地迴環地址、保留地址,點分十進制)可用於簡單的測試網卡是否故障。表示本機。
B:端口號:  (1) 用於標識進程的邏輯地址。不一樣的進程都有不一樣的端口標識。
                   (2) 端口:要將數據發送到對方指定的應用程序上,爲了標識這些應用程序,因此給這些網絡應用程序都用數字進行標識。爲了方便稱呼這些數字,則將這些數字稱爲端口。(此端口是一個邏輯端口)
C: 傳輸協議:通信的規則。例如:TCP、UDP協議(比如兩我的得用同一種語言進行交流)

2.  socket 編程  網絡

要想理解socket,就要先來理解TCP,UDP協議

     TCP/IP(Transmission Control Protocol/Internet Protocol)即傳輸控制協議/網間協議,定義了主機如何連入因特網及數據如何再它們之間傳輸的標準,

從字面意思來看TCP/IP是TCP和IP協議的合稱,但實際上TCP/IP協議是指因特網整個TCP/IP協議族。不一樣於ISO模型的七個分層,TCP/IP協議參考模型把全部的TCP/IP系列協議歸類到四個抽象層中

應用層:TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet 等等

傳輸層:TCP,UDP

網絡層:IP,ICMP,OSPF,EIGRP,IGMP

數據鏈路層:SLIP,CSLIP,PPP,MTU

每一抽象層創建在低一層提供的服務上,而且爲高一層提供服務,看起來大概是這樣子的

    咱們能夠利用ip地址+協議+端口號惟一標示網絡中的一個進程。可以惟一標示網絡中的進程後,它們就能夠利用socket進行通訊了,咱們常常把socket翻譯爲套接字,socket是在應用層和傳輸層(TCP/IP協議族通訊)之間的一個抽象層,是一組接口,它把TCP/IP層複雜的操做抽象爲幾個簡單的接口供應用層調用已實現進程在網絡中通訊。

    應用程序兩端經過「套接字」向網絡發出請求或者應答網絡請求。能夠把socket理解爲通訊的把手(hand)

    socket起源於UNIX,在Unix一切皆文件哲學的思想下,socket是一種"打開—讀/寫—關閉"模式的實現,服務器和客戶端各自維護一個"文件",在創建鏈接打開後,能夠向本身文件寫入內容供對方讀取或者讀取對方內容,通信結束時關閉文件。socket的英文原義是「插槽」或「插座」,就像咱們家裏座機同樣,若是沒有網線的那個插口,電話是沒法通訊的。Socket是實現TCP,UDP協議的接口,便於使用TCP,UDP。

 

通訊流程框架

流程:socket

# 流程描述:
# 
# 1 服務器根據地址類型(ipv4,ipv6)、socket類型、協議建立socket
# 
# 2 服務器爲socket綁定ip地址和端口號
# 
# 3 服務器socket監聽端口號請求,隨時準備接收客戶端發來的鏈接,這時候服務器的socket並無被打開
# 
# 4 客戶端建立socket
# 
# 5 客戶端打開socket,根據服務器ip地址和端口號試圖鏈接服務器socket
# 
# 6 服務器socket接收到客戶端socket請求,被動打開,開始接收客戶端請求,直到客戶端返回鏈接信息。這時候socket進入阻塞狀態,所謂阻塞即accept()方法一直等到客戶端返回鏈接信息後才返回,開始接收下一個客戶端鏈接請求
# 
# 7 客戶端鏈接成功,向服務器發送鏈接狀態信息
# 
# 8 服務器accept方法返回,鏈接成功
# 
# 9 客戶端向socket寫入信息(或服務端向socket寫入信息)
# 
# 10 服務器讀取信息(客戶端讀取信息)
# 
# 11 客戶端關閉
# 
# 12 服務器端關閉

 

來一個簡單的例子來看一下,服務端和客戶端之間相互通訊post

2.1   serve端測試

 1 import socket
 2 sk = socket.socket()
 3 print(sk)
 4 
 5 address = ("127.0.0.1",9000)
 6 sk.bind(address)
 7 sk.listen(3)                        #表示最多隻能等待三人
 8 print("waiting...............")
 9 conn,addr = sk.accept()
10 #inp = input(">>>")
11 #conn.send(byte(inp,"utf8"))
12 data = conn.recv(1024)
13 print(data)
14 conn.close()
15 sk.close()

client端編碼

 1 import socket
 2 sk = socket.socket()
 3 print(sk)
 4 
 5 address = ("127.0.0.1",9000)
 6 sk.connect(address)
 7 data = sk.send(bytes("haha","utf8"))   #阻塞
 8 
 9 #print(str(data,"utf8"))
10 sk.close()
11 print(sk)

這樣就簡單實現了服務端和客戶端之間的一次通訊,可是有時候咱們並非只進行一次通訊,咱們也許會有好幾回,也能夠中止聊天和另一個用戶聊,因此呢這時候就能夠用到循環了,能夠再看下面一個例子就能夠當作是屌絲追女神spa

服務端:

 1 import socket
 2 sk = socket.socket()
 3 print(sk)
 4 address = ("127.0.0.1",9000)
 5 sk.bind(address)                        #爲socket綁定IP和端口號       
 6 sk.listen(3)                            #監聽設置端口等待客戶端的請求
 7 print("waiting...............")
 8 while 1:
 9     conn,addr = sk.accept()              #accept阻塞,直到有客戶端來鏈接
10     #print(coon)
11     #print(sk.accept())
12     print(addr)
13     while 1:
14         data = conn.recv(1024)
15         # try:          #若是在客戶端直接暫停  進行異常處理
16         #     data = conn.recv(1024)
17         # except Exception:
18         #     break
19         print("......",str(data,"utf8"))
20         if not data:break
21         inp = input(">>>")
22         conn.send(bytes(inp,"utf8"))
23 sk.close()

客戶端:

 1 import socket
 2 sk = socket.socket()
 3 print(sk)
 4 
 5 address = ("127.0.0.1",9000)
 6 sk.connect(address)
 7 
 8 while True:
 9     inp = input(">>>")
10     if inp == "exit":
11         break
12     sk.send(bytes(inp,"utf8"))
13     data = sk.recv(1024)
14     print(str(data,"utf8"))
15 sk.close()
注意:

1  一收一發

2   client_data=conn.recv(1024)        

if  那邊send一個空數據  這邊recv爲空,則recv繼續阻塞,等待其餘的數據。因此聊天的時候好好聊,別發空數據。 

3. 遠程執行命令

咱們但願不只能在服務端和客戶端之間進行交流,有時候咱們也但願能在一端執行命令(dir,ifconfig,cd等等),另一端顯示結果     

那麼咱們直接來看例子,

cmd_serve端

 1 import socket,subprocess#詞模塊下只有一個參數
 2 sk = socket.socket()
 3 print(sk)
 4 address = ("127.0.0.1",9000)
 5 sk.bind(address)
 6 sk.listen(3)
 7 print("waiting...............")
 8 while 1:
 9     conn,addr = sk.accept()
10     #print(coon)
11     #print(sk.accept())
12     print(addr)
13     while 1:
14         try:          #若是在客戶端直接暫停處理異常
15             data = conn.recv(1024)
16         except Exception:
17             break
18         if not data:break
19         print("......", str(data, "utf8"))
20         obj = subprocess.Popen(data.decode("utf8"),shell = True,stdout = subprocess.PIPE)
21         cmd_result = obj.stdout.read()
22         result_len = bytes(str(len(cmd_result)),"utf8")
23         print(">>>>>>>>>>",result_len)
24         conn.sendall(result_len)               #粘包現象
#解決粘包conn.recv(1024)
25 conn.sendall(cmd_result) 26 sk.close()
注意:

 1 sendall並不會把數據直接所有發送到客戶端,而是將全部的數據都放到緩衝區(理解成一艘艘貨船),緩衝區一次最多發送1024字節的數據到客戶端

              2 好比第一次的結果有1124字節,那麼放在兩艘船上,一艘滿的,一艘只有100字節;那麼這一次只會講滿的1024字節結果發送到客戶端,程序並不會阻塞在這裏,會繼續向下執行,recv新的命令執行,好比第二次的結果有200字節數據,那麼這兩百字節的結果也會放到剛纔未滿的貨船上總共300字節一塊兒發送過去。 

cmd_client端 

 1 import socket
 2 sk = socket.socket()
 3 print(sk)
 4 
 5 address = ("127.0.0.1",9000)
 6 sk.connect(address)
 7 
 8 while True:
 9     inp = input(">>>")
10     if inp == "exit":
11         break
12     sk.send(bytes(inp,"utf8"))
13     result_len = int(str(sk.recv(1024),"utf8"))
14     sk.sendall('111') #解決粘包問題
15     print(result_len)
16     data = bytes()
17     while len(data) != result_len:
18         recv = sk.recv(1024)
19         data += recv
20     print(str(data,"gbk"))
21 sk.close()

 

這樣就能夠實如今客戶端輸入命令查看信息,在服務端就能夠按到命令的端口號以及IP地址,也同事處理了粘包的問題

4.   編碼轉換指示

4.1  在PY3中:只有str和bytes2種編碼

  str:unicode(萬國碼)

  bytes:(十六進制)

1 s='hello袁浩'
2 print(type(s))              #<class 'str'>

4.2  編碼規則:

  

 1         # 規則
 2 # str>>>>>>>>>>>>>>bytes:編碼
 3 
 4 b=bytes(s,'utf8')
 5 print(b)#b'hello\xe8\xa2\x81\xe6\xb5\xa9'   #utf8規則下的bytes類型
 6 
 7 b2=s.encode('utf8')
 8 print(b2)#b'hello\xe8\xa2\x81\xe6\xb5\xa9'  #utf8規則下的bytes類型
 9 
10 
11 b3=s.encode('gbk')
12 print('gbk編碼下的bytes數據:',b2)# b'hello\xd4\xac\xba\xc6'
13 
14 
15 
16 # bytes>>>>>str:解碼
17 
18 # s=str(b2,'gbk')
19 # print(s)#hello琚佹旦 亂碼了
20 
21 # # 解碼方法1:
22 # s=str(b2,'utf8')
23 # print(s)#hello袁浩  #str數據類型
24 #
25 # # 解碼方法2:
26 # s2=b2.decode('utf8')
27 #
28 # print(s2)#hello袁浩
29 
30 # s3=b3.decode('gbk')
31 # print(s3)#hello袁浩

5.文件上傳:

 1 import socket,os
 2 ip_port=("127.0.0.1",8898)
 3 sk=socket.socket()
 4 sk.bind(ip_port)
 5 sk.listen(5)
 6 BASE_DIR=os.path.dirname(os.path.abspath(__file__))
 7 
 8 while True:
 9     print("waiting connect")
10     conn,addr=sk.accept()
11     flag = True
12     while flag:
13 
14             client_bytes=conn.recv(1024)
15             client_str=str(client_bytes,"utf8")
16             func,file_byte_size,filename=client_str.split("|",2)
17 
18             path=os.path.join(BASE_DIR,'yuan',filename)
19             has_received=0
20             file_byte_size=int(file_byte_size)
21 
22             f=open(path,"wb")
23             while has_received<file_byte_size:
24                 data=conn.recv(1024)
25                 f.write(data)
26                 has_received+=len(data)
27             print("ending")
28             f.close()
29 
30 #----------------------------------------------client
31 #----------------------------------------------
32 import socket
33 import re,os,sys
34 ip_port=("127.0.0.1",8898)
35 sk=socket.socket()
36 sk.connect(ip_port)
37 BASE_DIR=os.path.dirname(os.path.abspath(__file__))
38 print("客戶端啓動....")
39 
40 while True:
41     inp=input("please input:")
42 
43     if inp.startswith("post"):
44         method,local_path=inp.split("|",1)
45         local_path=os.path.join(BASE_DIR,local_path)
46         file_byte_size=os.stat(local_path).st_size
47         file_name=os.path.basename(local_path)
48         post_info="post|%s|%s"%(file_byte_size,file_name)
49         sk.sendall(bytes(post_info,"utf8"))
50         has_sent=0
51         file_obj=open(local_path,"rb")
52         while has_sent<file_byte_size:
53             data=file_obj.read(1024)
54             sk.sendall(data)
55             has_sent+=len(data)
56         file_obj.close()
57         print("上傳成功")
相關文章
相關標籤/搜索