【socket】基于TCP和UDP的Socket编程

socket


socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口,把复杂的TCP/IP协议族隐藏在socket接口后面,一组简单的接口就是全部,让socket去组织数据,以符合指定的协议。

【socket】基于TCP和UDP的Socket编程_第1张图片

套接字


套接字有两种:

基于文件类型的套接字家族:AF_UNIX

基于网络类型的套接字家族:AF_INET

套接字工作流程


【socket】基于TCP和UDP的Socket编程_第2张图片

基于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

你可能感兴趣的:(python)