【socket】基於TCP和UDP的Socket程式設計
阿新 • • 發佈:2019-02-16
socket
socket是應用層與TCP/IP協議族通訊的中間軟體抽象層,它是一組介面,把複雜的TCP/IP協議族隱藏在socket介面後面,一組簡單的介面就是全部,讓socket去組織資料,以符合指定的協議。
套接字
套接字有兩種:
基於檔案型別的套接字家族:AF_UNIX
基於網路型別的套接字家族:AF_INET
套接字工作流程
基於TCP協議的socket程式設計
簡單的基於TCP協議的socket
#伺服器端
import socket server=socket.socket(socket.AF_INET, socket.SOCK_STREAM)#AF_INET是基於網路的套接字,STREAM是TCP是面向流 ip_port=("10.171.24.42",8001) buffer_size=1024#最大接受的位元組資訊 back_log=5#最大掛起的連結數 server.bind(ip_port)#繫結 server.listen(back_log) conn,addr=server.accept()#阻塞直到有連結進來 data=conn.recv(buffer_size)#接收資訊 print("recv:",data.decode()) conn.send('ok'.encode("utf-8"))#傳送資訊 conn.close()#關閉連線 server.close()#關閉
#客戶端
import socket client=socket.socket(socket.AF_INET, socket.SOCK_STREAM)#AF_INET是基於網路的套接字,STREAM是TCP是面向流 ip_port=("10.171.24.42",8001) buffer_size=1024#最大接受的位元組資訊 back_log=5#最大掛起的連結數 client.connect(ip_port) client.send("hello".encode('utf-8')) data=client.recv(buffer_size)#接收資訊 print("recv:",data.decode()) client.close()#關閉
要是出現Adress已被佔用的錯誤,就在伺服器端bind前加上
server.setsockopt(sol_SOCKET,SO_REUSEADDR,1)
基於TCP協議 迴圈接收和傳送訊息
#伺服器端
import socket server=socket.socket(socket.AF_INET, socket.SOCK_STREAM)#AF_INET是基於網路的套接字,STREAM是TCP是面向流 ip_port=("10.171.24.42",8000) buffer_size=1024#最大接受的位元組資訊 back_log=5#最大掛起的連結數 server.bind(ip_port)#繫結 server.listen(back_log) while True: conn,addr=server.accept()#阻塞直到有連結進來 while True: data=conn.recv(buffer_size)#接收資訊 print("recv:",data.decode()) conn.send('ok'.encode("utf-8"))#傳送資訊 conn.close()#關閉連線 server.close()#關閉
#客戶端
import socket
client=socket.socket(socket.AF_INET, socket.SOCK_STREAM)#AF_INET是基於網路的套接字,STREAM是TCP是面向流
ip_port=("10.171.24.42",8000)
buffer_size=1024#最大接受的位元組資訊
back_log=5#最大掛起的連結數
client.connect(ip_port)
while True:
msg=input(">>:").strip()
client.send(msg.encode('utf-8'))
data=client.recv(buffer_size)#接收資訊
print("recv:",data.decode())
client.close()#關閉
基於TCP協議 實現遠端執行命令
#伺服器端
"""基於tcp實現遠端執行命令"""
import socket
import subprocess
tcp_server=socket.socket(socket.AF_INET, socket.SOCK_STREAM)#AF_INET是基於網路的套接字,STREAM是TCP是面向流
ip_port=("10.171.24.42",8002)
buffer_size=1024#最大接受的位元組資訊
back_log=5#最大掛起的連結數
tcp_server.bind(ip_port)#繫結
tcp_server.listen(back_log)
while True:
conn,addr=tcp_server.accept()#阻塞直到有連結進來
while True:
try: #try ...except 是因為基於tcp的套接字不能處理空,udp可以
cmd=conn.recv(buffer_size)#接收資訊
print("recv cmd:",cmd.decode())
res=subprocess.Popen(cmd.decode("utf-8"),shell=True,stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
stdin=subprocess.PIPE )
err=res.stderr.read()#看有沒有出錯
if err:#如果出錯了,返回錯誤
cmd_res=err
else:#沒出錯返回執行結果
cmd_res=res.stdout.read()
if not cmd_res:#如果那種沒有返回值的命令,如ls...就返回‘執行成功’
cmd_res="執行成功!".encode("utf-8")
conn.send(cmd_res.encode("gbk"))#傳送資訊 #這裡是gbk,因為是用的subprocess
except Exception as ee:
print(ee)
break
conn.close()#關閉連線
tcp_server.close()#關閉
#客戶端
"""基於tcp的套接字socket實現遠端執行命令"""
import socket
tcp_client=socket.socket(socket.AF_INET, socket.SOCK_STREAM)#AF_INET是基於網路的套接字,STREAM是TCP是面向流
ip_port=("10.171.24.42",8002)
buffer_size=1024#最大接受的位元組資訊
back_log=5#最大掛起的連結數
tcp_client.connect(ip_port)
while True:
cmd=input(">>:").strip()
if not cmd:continue
if cmd=="quit":break
tcp_client.send(cmd.encode('utf-8'))
cmd_res=tcp_client.recv(buffer_size)#接收資訊
print("執行結果是:",cmd_res.decode("gbk"))
tcp_client.close()#關閉
伺服器端的try...except是因為基於tcp的recv在自己這端緩衝區為空時阻塞
基於UDP協議的socket程式設計
簡單的基於UDP協議的socket
UDP相對於TCP,它伺服器端減少了listen()和accept(),並且TCP中是SOCK_STREAM,而UDP中是SOCK_DGRAM。
由於沒有建立連線,所以接收訊息時要加上地址addr,傳送的時候後邊要加上ip_port
注意,UDP的socket中是sendto和recvfrom
#伺服器端
import socket
udp_server=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)#AF_INET是基於網路的套接字,STREAM是TCP是面向流
ip_port=("10.171.24.42",8003)
buffer_size=1024#最大接受的位元組資訊
back_log=5#最大掛起的連結數
udp_server.bind(ip_port)#繫結
while True:
data,addr=udp_server.recvfrom(buffer_size)#接收資訊
print("recv:",data.decode("utf-8"))
udp_server.sendto('ok'.encode("utf-8"),addr)#傳送資訊
server.close()#關閉
#客戶端
import socket
udp_client=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)#AF_INET是基於網路的套接字,STREAM是TCP是面向流
ip_port=("10.171.24.42",8003)
buffer_size=1024#最大接受的位元組資訊
back_log=5#最大掛起的連結數
while True:
msg=input(">>:").strip()
udp_client.sendto(msg.encode('utf-8'),ip_port)
data=udp_client.recvfrom(buffer_size)#接收資訊
print("recv:", data.decode("utf-8"))
client.close()#關閉
基於UDP協議 實現遠端執行命令
#伺服器端
import socket
import subprocess
udp_server=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)#AF_INET是基於網路的套接字,STREAM是TCP是面向流
ip_port=("10.171.24.42",8002)
buffer_size=1024#最大接受的位元組資訊
back_log=5#最大掛起的連結數
udp_server.bind(ip_port)#繫結
while True:
cmd,addr=udp_server.recvfrom(buffer_size)#阻塞直到有連結進來
res=subprocess.Popen(cmd.decode("utf-8"),shell=True,stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
stdin=subprocess.PIPE )
err=res.stderr.read()#看有沒有出錯
if err:#如果出錯了,返回錯誤
cmd_res=err
else:#沒出錯返回執行結果
cmd_res=res.stdout.read()
if not cmd_res:#如果那種沒有返回值的命令,如ls...就返回‘執行成功’
cmd_res="執行成功!".encode("gbk")
udp_server.sendto(cmd_res,addr)#傳送資訊 #這裡是gbk,因為是用的subprocess
udp_server.close()#關閉
#客戶端
import socket
udp_client=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)#AF_INET是基於網路的套接字,STREAM是TCP是面向流
ip_port=("10.171.24.42",8002)
buffer_size=1024#最大接受的位元組資訊
back_log=5#最大掛起的連結數
while True:
cmd=input(">>:").strip()
if not cmd:continue
if cmd=="quit":break
udp_client.sendto(cmd.encode('utf-8'),ip_port)
cmd_res,addr=udp_client.recvfrom(buffer_size)#接收資訊
print("執行結果是:",cmd_res.decode("gbk"),end='')
udp_client.close()#關閉
YCP