asp.core api 通过socket和服务器通信发送udp_python socket之TCP/UDP
#coding=utf-8
#?socket
#網絡中進程之間通信:網絡層的“ip地址”可以唯一標識網絡中的主機,而傳輸層的“協議+端口”可以唯一標識主機中的應用程序(進程)。利用ip地址,協議,端口就可以標識網絡的進程了,網絡中的進程通信就可以利用這個標志與其它進程進行交互
#socket(簡稱?套接字)?是進程間通信的一種方式,它與其他進程間通信的一個主要不同是:它能實現不同主機間的進程間通信,我們網絡上各種各樣的服務大多都是基于 Socket 來完成通信的;例如我們每天瀏覽網頁、QQ 聊天、收發 email 等等
#創建socket: Python 中?使用socket 模塊的函數 socket 就可以完成:socket.socket(AddressFamily, Type),函數 socket.socket 創建一個 socket,返回該 socket 的描述符,該函數帶有兩個參數:Address Family:可以選擇 AF_INET(用于 Internet 進程間通信)?或者 AF_UNIX(用于同一臺機器進程間通信),實際工作中常用AF_INET;Type:套接字類型,可以是 SOCK_STREAM(流式套接字,主要用于 TCP 協議)或者 SOCK_DGRAM(數據報套接字,主要用于 UDP 協議)
#創建一個tcp?socket(tcp套接字)
import?socket
s?=?socket.socket(socket.AF_INET,?socket.SOCK_STREAM)
print('Socket?Created')#Socket?Created
#創建一個udp?socket(udp套接字)
import?socket
s?=?socket.socket(socket.AF_INET,?socket.SOCK_DGRAM)
print('Socket?Created')#Socket?Created
#創建一個udp客戶端程序的流程是簡單,具體步驟如下:創建客戶端套接字;發送/接收數據;關閉套接字
#發送數據
#coding=utf-8
from?socket?import?*
#1.?創建套接字
udpSocket?=?socket(AF_INET,?SOCK_DGRAM)
#2.?準備接收方的地址
sendAddr?=?('192.168.80.1',?8080)
#3.?從鍵盤獲取數據
sendData?=?input("請輸入要發送的數據:")
#4.?發送數據到指定的電腦上
udpSocket.sendto(sendData.encode('utf-8'),?sendAddr)
#5.?關閉套接字
udpSocket.close()
#接收數據
#coding=utf-8
from?socket?import?*
#1.?創建套接字
udpSocket?=?socket(AF_INET,?SOCK_DGRAM)
#2.?準備接收方的地址
sendAddr?=?('192.168.80.1',?8080)
#3.?從鍵盤獲取數據
sendData?=?input("請輸入要發送的數據:")
#4.?發送數據到指定的電腦上
udpSocket.sendto(sendData.encode('utf-8'),?sendAddr)
#5.?等待接收對方發送的數據
recvData?=?udpSocket.recvfrom(1024)?#?1024表示本次接收的最大字節數
#6.?顯示對方發送的數據
print(recvData)#(b'haha1',?('192.168.80.1',?8080))
#7.?關閉套接字
udpSocket.close()
#每重新運行一次網絡程序,端口不一樣的原因在于,當重新運行時,如果沒有確定到底用哪個,系統默認會隨機分配。記住一點:這個網絡程序在運行的過程中,這個就唯一標識這個程序,所以如果其他電腦上的網絡程序如果想要向此程序發送數據,那么就需要向這個數字(即端口)標識的程序發送即可
#udp綁定信息
#coding=utf-8
from?socket?import?*
#1.?創建套接字
udpSocket?=?socket(AF_INET,?SOCK_DGRAM)
#2.?綁定本地的相關信息,如果一個網絡程序不綁定,則系統會隨機分配
bindAddr?=?('',?7788)?#?ip地址和端口號,ip一般不用寫,表示本機的任何一個ip
udpSocket.bind(bindAddr)
#3.?等待接收對方發送的數據
recvData?=?udpSocket.recvfrom(1024)?#?1024表示本次接收的最大字節數
#4.?顯示接收到的數據
print(recvData)#(b'thanks',?('192.168.80.1',?8080))
#5.?關閉套接字
udpSocket.close()
#一個udp網絡程序,可以不綁定,此時操作系統會隨機進行分配一個端口,如果重新運行次程序端口可能會發生變化,一個udp網絡程序,也可以綁定信息(ip地址,端口號),如果綁定成功,那么操作系統用這個端口號來進行區別收到的網絡數據是否是此進程的
#udp應用:echo服務器,echo服務端循環等待對方發數據,再發送回去
#coding=utf-8
from?socket?import?*
#1.?創建套接字
udpSocket?=?socket(AF_INET,?SOCK_DGRAM)
#2.?綁定本地的相關信息
bindAddr?=?('',?7788)?#?ip地址和端口號,ip一般不用寫,表示本機的任何一個ip
udpSocket.bind(bindAddr)
num?=?1
while?True:
????#3.?等待接收對方發送的數據
????recvData?=?udpSocket.recvfrom(1024)?#?1024表示本次接收的最大字節數
????#4.?將接收到的數據再發送給對方
????udpSocket.sendto(recvData[0],?recvData[1])
????#5.?統計信息
????print('已經將接收到的第%d個數據返回給對方,內容為:%s'%(num,recvData[0]))
????num+=1
#5.?關閉套接字
udpSocket.close()
#udp應用:聊天室
#coding=utf-8
from?socket?import?*
from?time?import?ctime
#1.?創建套接字
udpSocket?=?socket(AF_INET,?SOCK_DGRAM)
#2.?綁定本地的相關信息
bindAddr?=?('',?7788)?#?ip地址和端口號,ip一般不用寫,表示本機的任何一個ip
udpSocket.bind(bindAddr)
while?True:
????#3.?等待接收對方發送的數據
????recvData?=?udpSocket.recvfrom(1024)?#?1024表示本次接收的最大字節數
????#4.?打印信息
????print('【%s】%s:%s'%(ctime(),recvData[1][0],recvData[0]))#【Mon?Nov?23?11:25:58?2020】192.168.80.1:b'thank2'
#5.?關閉套接字
udpSocket.close()
#1. udp是TCP/IP協議族中的一種協議能夠完成不同機器上的程序間的數據通信;2. udp服務器、客戶端:udp的服務器和客戶端的區分:往往是通過請求服務和提供服務來進行區分;請求服務的一方稱為:客戶端;提供服務的一方稱為:服務器;3. udp綁定問題:一般情況下,服務器端,需要綁定端口,目的是為了讓其他的客戶端能夠正確發送到此進程,客戶端,一般不需要綁定,而是讓操作系統隨機分配,這樣就不會因為需要綁定的端口被占用而導致程序無法運行的情況
#TFTP(Trivial File Transfer Protocol,簡單文件傳輸協議):是TCP/IP協議族中的一個用來在客戶端與服務器之間進行簡單文件傳輸的協議。適合在局域網進行傳遞,端口號為69,基于UDP實現
#TFTP服務器默認監聽69號端口,當客戶端發送“下載”請求(即讀請求)時,需要向服務器的69端口發送,服務器若批準此請求,則使用一個新的、臨時的?端口進行數據傳輸。當服務器找到需要現在的文件后,會立刻打開文件,把文件中的數據通過TFTP協議發送給客戶端,如果文件的總大小較大(比如3M),那么服務器分多次發送,每次會從文件中讀取512個字節的數據發送過來,因為發送的次數有可能會很多,所以為了讓客戶端對接收到的數據進行排序,所以在服務器發送那512個字節數據的時候,會多發2個字節的數據,用來存放序號,并且放在512個字節數據的前面,序號是從1開始的。因為需要從服務器上下載文件時,文件可能不存在,那么此時服務器就會發送一個錯誤的信息過來,為了區分服務發送的是文件內容還是錯誤的提示信息,所以又用了2個字節?來表示這個數據包的功能(稱為操作碼),并且在序號的前面。
"""
操作碼??????????????????功能
1???????????????????????讀請求,即下載
2???????????????????????寫請求,即上傳
3???????????????????????表示數據包,即DATA
4???????????????????????確認碼,即ACK
5???????????????????????錯誤
"""
#因為udp的數據包不安全,即發送方發送是否成功不能確定,所以TFTP協議中規定,為了讓服務器知道客戶端已經接收到了剛剛發送的那個數據包,所以當客戶端接收到一個數據包的時候需要向服務器進行發送確認信息,即發送收到了,這樣的包成為ACK(應答包)。為了標記數據已經發送完畢,所以規定,當客戶端接收到的數據小于516(2字節操作碼+2個字節的序號+512字節數據)時,就意味著服務器發送完畢了。
#在192.168.80.128上搭建TFTP服務器,1、yum?install?xinetd?tftp?tftp-server????????#?root?用戶執行
#?2、配置tftp-server
"""
#?[root@localhost?~]#?cat?/etc/xinetd.d/tftp?
#?default:?off
#?description:?The?tftp?server?serves?files?using?the?trivial?file?transfer?\
#????protocol.??The?tftp?protocol?is?often?used?to?boot?diskless?\
#????workstations,?download?configuration?files?to?network-aware?printers,?\
#????and?to?start?the?installation?process?for?some?operating?systems.
service?tftp
{
????socket_type????????=?dgram
????protocol???????????=?udp
????wait???????????????=?yes
????user???????????????=?root
????server?????????????=?/usr/sbin/in.tftpd
????server_args????????=?-s?/var/lib/tftpboot?-c???#?注意這行,如果允許上傳,一定要加上參數?-c
????disable????????????=?no???#?這行默認為yes,改成no,允許
????per_source?????????=?11
????cps????????????????=?100?2
????flags??????????????=?IPv4
}
"""
#3、啟動服務
"""
[root@localhost?~]#systemctl?restart?xinetd.service?
[root@localhost?~]#?netstat?-a?|?grep?tftp?
udp????????0??????0?0.0.0.0:tftp????????????0.0.0.0:*??????????????????????????
udp6???????0??????0?[::]:tftp???????????????[::]:*?
[root@localhost?~]#?netstat?-tunap?|?grep?:69
udp????????0??????0?0.0.0.0:69??????????????0.0.0.0:*???????????????????????????30014/xinetd????????
udp6???????0??????0?:::69???????????????????:::*????????????????????????????????1/systemd?
"""
#4、如果上傳時出現"連接請求失敗"的提示,請確保tftp服務的文件存放目錄權限設置正確
#解決辦法:chmod ?0777 ?/var/lib/tftpboot ??#其中tftpboot為上傳和下載文件存儲目錄
#coding:utf-8
from?socket?import?*
import?struct
import?sys
if?len(sys.argv)?!=?2:
????print('-'*30)
????print("tips:")
????print("python?network.py?192.168.80.128")
????print('-'*30)
????exit()
else:
????ip?=?sys.argv[1]
#?創建udp套接字
udpSocket?=?socket(AF_INET,?SOCK_DGRAM)
#構造下載請求數據
cmd_buf?=?struct.pack("!H8sb5sb".encode('utf-8'),1,"test.jpg".encode('utf-8'),0,"octet".encode('utf-8'),0)
#發送下載文件請求數據到指定服務器
sendAddr?=?('192.168.80.128',?69)
udpSocket.sendto(cmd_buf,?sendAddr)
p_num?=?0
recvFile?=?''
while?True:
????recvData,recvAddr?=?udpSocket.recvfrom(1024)
????recvDataLen?=?len(recvData)
????#?print?recvAddr?#?for?test
????#?print?len(recvData)?#?for?test
????cmdTuple?=?struct.unpack("!HH",?recvData[:4])
????#?print?cmdTuple?#?for?test
????cmd?=?cmdTuple[0]
????currentPackNum?=?cmdTuple[1]????????
????if?cmd?==?3:?#是否為數據包
????????#?如果是第一次接收到數據,那么就創建文件
????????if?currentPackNum?==?1:
????????????recvFile?=?open("test.jpg",?"ab")
????????#?包編號是否和上次相等
????????if?p_num+1?==?currentPackNum:
????????????recvFile.write(recvData[4:])
????????????p_num?+=1
????????????print('(%d)次接收到的數據'%(p_num))
????????????ackBuf?=?struct.pack("!HH",4,p_num)
????????????udpSocket.sendto(ackBuf,?recvAddr)
????????#?如果收到的數據小于516則認為出錯
????????if?recvDataLen<516:
????????????recvFile.close()
????????????print('已經成功下載!!!')
????????????break
????elif?cmd?==?5:?#是否為錯誤應答
????????print("error?num:%d"%currentPackNum)
????????break
udpSocket.close()
"""
PS?D:\python>?python?network.py?test.jpg
(1)次接收到的數據
(2)次接收到的數據
已經成功下載!!!
"""
#網絡編程中的廣播
#coding=utf-8
import?socket,?sys
dest?=?('',?7788)
#?創建udp套接字
s?=?socket.socket(socket.AF_INET,?socket.SOCK_DGRAM)
#?對這個需要發送廣播數據的套接字進行修改設置,否則不能發送廣播數據
s.setsockopt(socket.SOL_SOCKET,?socket.SO_BROADCAST,1)
#?以廣播的形式發送數據到本網絡的所有電腦中
s.sendto("Hi".encode('utf-8'),?dest)
print("等待對方回復(按ctrl+c退出)")
while?True:
????(buf,?address)?=?s.recvfrom(2048)
????print("Received?from?%s:?%s"?%?(address,?buf))
"""客戶端(UDP協議局域網廣播)"""
import?socket
s?=?socket.socket(socket.AF_INET,?socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET,?socket.SO_BROADCAST,?1)
PORT?=?7788
s.bind(('',?PORT))
print('Listening?for?broadcast?at?',?s.getsockname())
while?True:
????data,?address?=?s.recvfrom(65535)
????print('Server?received?from?{}:{}'.format(address,?data.decode('utf-8')))
#如果想要完成一個tcp服務器的功能,需要的流程如下:socket創建一個套接字;bind綁定ip和port;listen使套接字變為可以被動鏈接;accept等待客戶端的鏈接;recv/send接收發送數據
#先運行這段代碼作為服務端,打開客戶端鏈接服務端,發送信息“哈哈”,客戶端會收到:[2020-11-23 16:01:25.449]# RECV ASCII>thank you !
#coding=utf-8
from?socket?import?*
#?創建socket
tcpSerSocket?=?socket(AF_INET,?SOCK_STREAM)
#?綁定本地信息
address?=?('',?7788)
tcpSerSocket.bind(address)
#?使用socket創建的套接字默認的屬性是主動的,使用listen將其變為被動的,這樣就可以接收別人的鏈接了
tcpSerSocket.listen(5)
#?如果有新的客戶端來鏈接服務器,那么就產生一個新的套接字專門為這個客戶端服務器;newSocket用來為這個客戶端服務;tcpSerSocket就可以省下來專門等待其他新客戶端的鏈接
newSocket,?clientAddr?=?tcpSerSocket.accept()
#?接收對方發送過來的數據,最大接收1024個字節
recvData?=?newSocket.recv(1024)
recvData?=?recvData.decode('gb2312')#中文編碼
print('接收到的數據為:',recvData)
#?發送一些數據到客戶端
newSocket.send("thank?you?!".encode('utf-8'))
#?關閉為這個客戶端服務的套接字,只要關閉了,就意味著為不能再為這個客戶端服務了,如果還需要服務,只能再次重新連接
newSocket.close()
#?關閉監聽套接字,只要這個套接字關閉了,就意味著整個程序不能再接收任何新的客戶端的連接
tcpSerSocket.close()
#tcp客戶端構建流程
#coding:utf-8
from?socket?import?*
#?創建socket
tcpClientSocket?=?socket(AF_INET,?SOCK_STREAM)
#?鏈接服務器
serAddr?=?('192.168.80.1',?7788)
tcpClientSocket.connect(serAddr)
#?提示用戶輸入數據
sendData?=?input("請輸入要發送的數據:")
tcpClientSocket.send(sendData.encode('utf-8'))
#?接收對方發送過來的數據,最大接收1024個字節
recvData?=?tcpClientSocket.recv(1024).decode('gb2312')
print('接收到的數據為:',recvData)
#?關閉套接字
tcpClientSocket.close()
#模擬QQ聊天
#客戶端
#coding=utf-8
from?socket?import?*
#?創建socket
tcpClientSocket?=?socket(AF_INET,?SOCK_STREAM)
#?鏈接服務器
serAddr?=?('192.168.80.1',?7788)
tcpClientSocket.connect(serAddr)
while?True:
????#?提示用戶輸入數據
????sendData?=?input("send:")
????if?len(sendData)>0:
????????tcpClientSocket.send(sendData.encode('utf-8'))
????else:
????????break
????#?接收對方發送過來的數據,最大接收1024個字節
????recvData?=?tcpClientSocket.recv(1024)
????print('recv:',recvData.decode('gb2312'))
#?關閉套接字
tcpClientSocket.close()
#服務器端
#coding=utf-8
from?socket?import?*
#?創建socket
tcpSerSocket?=?socket(AF_INET,?SOCK_STREAM)
#?綁定本地信息
address?=?('',?7788)
tcpSerSocket.bind(address)
#?使用socket創建的套接字默認的屬性是主動的,使用listen將其變為被動的,這樣就可以接收別人的鏈接了
tcpSerSocket.listen(5)
while?True:
????#?如果有新的客戶端來鏈接服務器,那么就產生一個信心的套接字專門為這個客戶端服務器,????#?newSocket用來為這個客戶端服務,????#?tcpSerSocket就可以省下來專門等待其他新客戶端的鏈接
????newSocket,?clientAddr?=?tcpSerSocket.accept()
????while?True:
????????#?接收對方發送過來的數據,最大接收1024個字節
????????recvData?=?newSocket.recv(1024).decode('gb2312')
????????#?如果接收的數據的長度為0,則意味著客戶端關閉了鏈接
????????if?len(recvData)>0:
????????????print('recv:',recvData)
????????else:
????????????break
????????#?發送一些數據到客戶端
????????sendData?=?input("send:")
????????newSocket.send(sendData.encode('utf-8'))
????#?關閉為這個客戶端服務的套接字,只要關閉了,就意味著為不能再為這個客戶端服務了,如果還需要服務,只能再次重新連接
????newSocket.close()
#?關閉監聽套接字,只要這個套接字關閉了,就意味著整個程序不能再接收任何新的客戶端的連接
tcpSerSocket.close()
#listen的隊列長度
#服務器端
#coding=utf-8
from?socket?import?*
from?time?import?sleep
#?創建socket
tcpSerSocket?=?socket(AF_INET,?SOCK_STREAM)
#?綁定本地信息
address?=?('',?7788)
tcpSerSocket.bind(address)
connNum?=?int(input("請輸入要最大的鏈接數:"))
#?使用socket創建的套接字默認的屬性是主動的,使用listen將其變為被動的,這樣就可以接收別人的鏈接了。代表可建立socket連接的排隊的個數windows,mac 此連接參數有效,Linux 此連接參數無效,默認最大
#bacuklog的定義:在進程正理一個一個連接請求的時候,可能還存在其它的連接請求。因為TCP連接是一個過程,所以可能存在一種半連接的狀態,有時由于同時嘗試連接的用戶過多,使得服務器進程無法快速地完成連接請求。如果這個情況出現了,服務器進程希望內核如何處理呢?內核會在自己的進程空間里維護一個隊列以跟蹤這些完成的連接但服務器進程還沒有接手處理或正在進行的連接,這樣的一個隊列內核不可能讓其任意大,所以必須有一個大小的上限。這個backlog告訴內核使用這個數值作為上限。
#當客戶端請求到來時,服務器會處理他們的請求,在你的代碼中就是創建一個線程來處理。那么請求多了之后就會創建很多個線程,這樣服務器資源總會到達上限。backlog為5,實際上不是限制處理的線程為5,而是當服務器忙不過來了,內核會hold住一個長度為5的隊列,一旦服務器忙過來了,就會從這個隊列中拿出一個來處理,直到隊列為空。
tcpSerSocket.listen(connNum)
while?True:
????#?如果有新的客戶端來鏈接服務器,那么就產生一個新的套接字專門為這個客戶端服務器
????newSocket,?clientAddr?=?tcpSerSocket.accept()
????print(clientAddr)
????sleep(1)
#客戶端運行
#coding=utf-8
from?socket?import?*
connNum?=?input("請輸入要鏈接服務器的次數:")
for?i?in?range(int(connNum)):
????s?=?socket(AF_INET,?SOCK_STREAM)
????s.connect(("192.168.80.1",?7788))
????print(i)
#listen中的black表示已經建立鏈接和半鏈接的總數,如果當前已建立鏈接數和半鏈接數以達到設定值,那么新客戶端就不會connect成功,而是等待服務器
總結
以上是生活随笔為你收集整理的asp.core api 通过socket和服务器通信发送udp_python socket之TCP/UDP的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python文件写入字典格式输出_Pyt
- 下一篇: python修改类的属性值_python