饮冰三年-人工智能-Python-19 Python网络编程

Socket:套接字。作用:我们只需要安照socket的规定去编程,就不需要深入理解tcp/udp协议也可以实现

1:TCP协议

1.1  客户端服务端循环收发消息

# 1:引入stock模块(导包)
import socket
#2:创建服务端对象
tcp_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#3:绑定接口地址和端口号
ip_port=("127.0.0.1",8000)
back_log=5
buffer_size=1024
tcp_server.bind(ip_port)
#4: 开启监听(设置监听数量)
tcp_server.listen(back_log)
print("服务端开始运行了")
# 5:准备接收消息
conn, add = tcp_server.accept()
while True:
    #6:接收消息
    data=conn.recv(buffer_size)
    print("客户端发送的消息是:",data.decode("utf-8"))
    #7:发送消息
    conn.send(data.upper())
# 8:关闭连接
conn.close()
# 9:关闭服务端对象
tcp_server.close()
服务端
#1:引入模块
from socket import *
#2:创建对象
tcp_client = socket(AF_INET,SOCK_STREAM)
#3:建立连接
ip_port=("127.0.0.1",8000)
buffer_size=1024
tcp_client.connect(ip_port)
while True:
    msg=input("请输入待发送的消息:")
    #4:发消息
    tcp_client.send(msg.encode("utf-8"))
    # 5:收消息
    data=tcp_client.recv(buffer_size)
    print("收到服务端传来的消息",data.decode("utf-8"))
tcp_client.close()
客户端

1.2 服务端循环链接请求来收发消息

# 1:引入stock模块(导包)
import socket
#2:创建服务端对象
tcp_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#3:绑定接口地址和端口号
ip_port=("127.0.0.1",8000)
back_log=5
buffer_size=1024
tcp_server.bind(ip_port)
#4: 开启监听(设置监听数量)
tcp_server.listen(back_log)
print("服务端开始运行了")
while True:
    # 5:准备接收消息
    conn, add = tcp_server.accept()
    while True:
        # 客户端断开连接的时候会报错
        try:
            # 6:接收消息
            data = conn.recv(buffer_size)
            # 据说Linux系统即使客户端断开连接也不会抛异常,这是需要手处理一下
            if not data:break
            print("客户端发送的消息是:", data.decode("utf-8"))
            # 7:发送消息
            conn.send(data.upper())
        except Exception:
            break
    # 8:关闭连接
    conn.close()
# 9:关闭服务端对象
tcp_server.close()
# 改进方向
#     1:把5和8放入到循环中,这样就可以实现多连接了
#     2:在内部连接中设置break方法
服务端
#1:引入模块
from socket import *
#2:创建对象
tcp_client = socket(AF_INET,SOCK_STREAM)
#3:建立连接
ip_port=("127.0.0.1",8000)
buffer_size=1024
tcp_client.connect_ex(ip_port)
while True:
    msg=input("请输入待发送的消息:")
    #如果不加这句,当输入换行时,服务器端会阻塞
    if len(msg)==0:
        continue
    #4:发消息
    tcp_client.send(msg.encode("utf-8"))
    # 5:收消息
    data=tcp_client.recv(buffer_size)
    print("收到服务端传来的消息",data.decode("utf-8"))
tcp_client.close()
客户端

 1.3 从代码层面解决 “通常每个套接字地址(协议/网络地址/端口)只允许使用一次。”问题,在bind前加下一句代码

tcp_server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

2:UDP协议

2.1  客户端服务端循环收发消息

# 1:引入stock模块(导包)
from socket import *
from time import strftime
#2:创建服务端对象
udp_server =socket(AF_INET,SOCK_DGRAM)
#3:绑定接口地址和端口号
ip_port=("127.0.0.1",8000)
back_log=5
buffer_size=1024
udp_server.bind(ip_port)
print("服务端开始运行了")
while True:
    while True:
        # 客户端断开连接的时候会报错
        try:
            # 6:接收消息
            data ,add= udp_server.recvfrom(buffer_size)
            print("客户端发送的消息是:", data.decode("utf-8"))
            # 7:发送消息
            time_fmt='%Y-%m-%d %X'
            data=strftime(time_fmt)
            udp_server.sendto(data.encode("utf-8"),add)
        except Exception:
            break

# 9:关闭服务端对象
udp_server.close()
# udp与tcp的不同之处
#     1:不需要连接s.listen()  监听和 s.accept()  被动接受TCP客户的连接,(阻塞式)等待连接的到来
#     2:通过recvfrom()接收数据;sendto()发送数据
#     3:既然没有连接,也就无所谓谁先启动,或者客户端关闭后是否会引发异常等情况
服务端
#1:引入模块
from socket import *
#2:创建对象
udp_client = socket(AF_INET,SOCK_DGRAM)
#3:建立连接
ip_port=("127.0.0.1",8000)
buffer_size=1024
udp_client.connect_ex(ip_port)
while True:
    msg=input("按任意键获取时间:")
    # 4:发消息
    udp_client.sendto(msg.encode("utf-8"), ip_port)
    # 5:收消息
    data, add = udp_client.recvfrom(buffer_size)
    print("收到服务端传来的时间", data)


tcp_client.close()
客户端

3:练习

  3.1 远程操作

  需要使用subprocess模块  

from socket import *
import subprocess
ip_port = ("127.0.0.1", 8089)
back_log = 5
buffer_size = 1024
tcp_server = socket(AF_INET, SOCK_STREAM)
tcp_server.bind(ip_port)
tcp_server.listen(back_log)
while True:
    conn, add = tcp_server.accept()
    print(add)
    while True:
        try:
            cmd = conn.recv(buffer_size);
            if not cmd:
                conn.close()
                break
            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()
            #
            conn.send(cmd_res)
        except Exception as e:
            print(e)
            conn.close()
            break
    conn.close()
top_server.close()
TCP-Server-1.0
from socket import *

ip_port=("127.0.0.1", 8089)
back_log = 5
buffer_size = 1024
tcp_client = socket(AF_INET, SOCK_STREAM)
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()
TCP-Client-1.0

  会出现粘包现象:1:tcp-ip内部算法优化,会把短时间内几个小的send信息包在一起发送(tcp-ip的send本身没有界限)2:一次发送量大,一次接受不全

from socket import *
import subprocess
ip_port = ("127.0.0.1", 8089)
back_log = 5
buffer_size = 1024
tcp_server = socket(AF_INET, SOCK_STREAM)
tcp_server.bind(ip_port)
tcp_server.listen(back_log)
while True:
    conn, add = tcp_server.accept()
    print(add)
    while True:
        try:
            cmd = conn.recv(buffer_size);
            if not cmd:
                conn.close()
                break
            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()
            # 为了解决粘包的问题,可以在发送的时候先把长度发过去
            length=str(len(cmd_res)).encode("utf-8")
            conn.send(length)
            # 如果直接这么发的话,会出现由于tcp优化出现的粘包情况。
            client_s = conn.recv(buffer_size);
            print("===>",client_s)
            if client_s==b"ready":
                conn.send(cmd_res)
        except Exception as e:
            print(e)
            conn.close()
            break
    conn.close()
top_server.close()
TCP-Server-2.0
from socket import *

ip_port=("127.0.0.1", 8089)
back_log = 5
buffer_size = 1024
tcp_client = socket(AF_INET, SOCK_STREAM)
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"))
    res_length=tcp_client.recv(buffer_size);

    #把获取到的长度转化成intleiixng
    cmd_res=""
    if res_length:
        tcp_client.send("ready".encode("utf-8"))
        res_length = int(res_length.decode("gbk"))
        print(res_length)
        # 循环遍历接收
        while len(cmd_res)<res_length:
            cur_res=tcp_client.recv(buffer_size).decode("gbk")
            cmd_res = cmd_res+cur_res
            print(cur_res)
tcp_client.close()
TCP-client-2.0
# 通过引入struct模块,编制一个报文长度,实现一次发送
import struct
from socket import *
import subprocess
ip_port = ("127.0.0.1", 8089)
back_log = 5
buffer_size = 1024
tcp_server = socket(AF_INET, SOCK_STREAM)
tcp_server.bind(ip_port)
tcp_server.listen(back_log)
while True:
    conn, add = tcp_server.accept()
    print(add)
    while True:
        try:
            cmd = conn.recv(buffer_size);
            if not cmd:
                conn.close()
                break
            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()
            # 为了解决粘包的问题,可以在发送的时候先把长度发过去
            length=struct.pack("i",len(cmd_res))
            conn.send(length)
            conn.send(cmd_res)
            print(struct.unpack("i",length)[0])
        except Exception as e:
            print(e)
            conn.close()
            break
    conn.close()
top_server.close()
TCP-Service # 通过引入struct模块,编制一个报文长度,实现一次发送
# 通过引入struct模块,编制一个报文长度,实现一次发送
from socket import *
import struct
ip_port=("127.0.0.1", 8089)
back_log = 5
buffer_size = 1024
tcp_client = socket(AF_INET, SOCK_STREAM)
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"))

    #把获取到的长度转化成intleiixng
    cmd_res=b''
    res_length = tcp_client.recv(4)
    length=struct.unpack("i",res_length)[0]
    # 循环遍历接收
    while len(cmd_res) < length:
        cur_res = tcp_client.recv(buffer_size)
        cmd_res = cmd_res + cur_res
    print(cmd_res.decode("gbk"))
tcp_client.close()
TCP-client-# 通过引入struct模块,编制一个报文长度,实现一次发送
# 通过引入struct模块,实现一次发送
# 通过socketServer实现并发
import struct
from socket import *
import subprocess
import socketserver


ip_port = ("127.0.0.1", 8089)
back_log = 5
buffer_size = 1024

# 定义一个实例化的类,主要用于收发消息
class My_server(socketserver.BaseRequestHandler):
    def handle(self):
        try:
            while True:
                # 收消息
                cmd = self.request.recv(buffer_size)
                if not cmd: break
                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()
                # 为了解决粘包的问题,可以在发送的时候先把长度发过去
                length = struct.pack("i", len(cmd_res))
                self.request.send(length)
                self.request.sendall(cmd_res)
        except Exception as e:
            print(e)


#通过线程创建对象
if __name__=="__main__":
    s=socketserver.ThreadingTCPServer(ip_port,My_server)
    s.serve_forever()
TCP-Service-4.0 通过socketServer实现并发
# 通过引入struct模块,编制一个报文长度,实现一次发送
from socket import *
import struct
ip_port=("127.0.0.1", 8089)
back_log = 5
buffer_size = 1024
tcp_client = socket(AF_INET, SOCK_STREAM)
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"))

    #把获取到的长度转化成intleiixng
    cmd_res=b''
    res_length = tcp_client.recv(4)
    length=struct.unpack("i",res_length)[0]
    # 循环遍历接收
    while len(cmd_res) < length:
        cur_res = tcp_client.recv(buffer_size)
        cmd_res = cmd_res + cur_res
    print(cmd_res.decode("gbk"))
tcp_client.close()
TCP-client-4.0 通过socketServer实现并发

   

猜你喜欢

转载自www.cnblogs.com/YK2012/p/9802222.html