1. 程式人生 > >【socket】基於TCP和UDP的Socket程式設計

【socket】基於TCP和UDP的Socket程式設計

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