zoukankan      html  css  js  c++  java
  • Python socket服务

    套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。

    1. 实现客户端发送字符,服务器返回大写的字符:

    服务器:

    import socketserver
    
    class MyTCPHandler(socketserver.BaseRequestHandler):         # 通过类的继承,实现
        def handle(self):                    # 重写父类的handle方法,所有的操作都在此方法中
            while True:                      # 循环,不停的接收从客户端来的数据
                try:
                    self.data = self.request.recv(1024).strip()         # 从客户端接收数据,每次收1024字节
                    print("{} send:".format(self.client_address), self.data)
                    self.request.send(self.data.upper())                 # 从服务器发送给客户端数据
                except ConnectionResetError as e:
                    print('Error: ',e)
                    break
    
    if __name__ == '__main__':
        host,port = 'localhost',9999
        server = socketserver.ThreadingTCPServer((host,port),MyTCPHandler)     # 通过多线程实现多个客户端连接,每个客户端连接都是一个线程
        server.serve_forever()                                                # 一直运行服务

    客户端:

    import socket
    
    client = socket.socket()                 # socket对象
    client.connect(('localhost',9999))      # 连接服务器地址和端口
    
    while True:                              # 循环,不停的输入发送数据
        con = input('>>>:').strip()
        if len(con) ==0: continue            # 不能发送空数据,否则会阻塞
        client.send(con.encode('utf-8'))    # 发送数据,必须是二进制的
        data = client.recv(1024)            # 接收服务器返回的数据
        print(data.decode())                # 打印 解码后的数据
    
    client.close()                      # 关闭

    2. 通过socket执行服务器命令:

    用法:直接在客户端输入处输入命令如:ipconfig

    服务器:

    import socket
    import os
    import threading
    
    def tcplink(sock, addr):
        print('Accept new connection from %s:%s...' % addr)
        while True:         # 和每个接入的客户端,进行多次数据通信
            data = sock.recv(1024)  # 接收客户端数据
            if not data or data.decode('utf-8') == 'exit':  # 如果客户端不发送数据或者发送了exit
                print('client disconnected.')
                break
            content = os.popen(data.decode('utf-8')).read() # 对发送来的数据执行cmd命令,获取结果
            if len(content) == 0:           #如果执行的命令结果为空的,就手动造一个结果。因为如果为空数据,会挂起,无法正常发送。
                content = 'cmd not exists.'
            sock.send(str(len(content.encode('utf-8'))).encode('utf-8')) # 发送数据的长度
            print('send length:', (len(content.encode('utf-8'))))
            # print('content,', content.encode('utf-8'))
            recv = sock.recv(1024)  # 因为上下都有一个send连在一起,可能发生粘包现象,为了防止这种情况,可以让客户端重新应答一下
            print('Answer:',recv.decode('utf-8'))
            sock.send(content.encode('utf-8'))        # 发送数据
            print('send finished.')
        sock.close()
        print('Connection from %s:%s closed.' % addr)
    
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 监听端口:
    s.bind(('127.0.0.1', 9999))
    s.listen(3)
    print('Waiting for connection...')
    
    while True:
        # 接受一个新连接:
        sock, addr = s.accept()
        # 创建新线程来处理TCP连接:
        t = threading.Thread(target=tcplink, args=(sock, addr))
        t.start()

    客户端:

    import socket
    
    # AF_INET 代表ipv4,SOCK_STREAM 代表TCP
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)     # 确定网络协议,生成对象
    s.connect(('127.0.0.1',9999)) # 连接服务器的地址和端口,元组的形式。
    while True:
        msg = input('>>:').strip()
        if len(msg) != 0:                  # 如果消息为空,会一直挂起,所以不能为空
            if msg =='exit':
                s.close()                     # 关闭连接
                print('Connection closed.')
                break
            s.send(msg.encode('utf-8'))       # 给服务器发送数据,必须是二进制的
            length = s.recv(1024)            # 首先接收服务器返回的将要接收的数据的长度信息。
            s.send(b'Ready to receive...')    # 发送接收命令
            length = int(length.decode('utf-8'))
            print('receive len:', length)
            data_len = 0
            data_recv = b''
            while data_len < length:    # 已经接收的信息的长度,如果小于总长度
                data = s.recv(1024)     # 从服务器接收数据
                data_recv += data
                data_len += len(data)
            print(data_recv.decode('utf-8'))  # 打印返回的数据。

    3. 通过socket传输文件:

    用法:get 文件名

    服务器:

    import socket
    import os
    import hashlib
    import threading
    
    def tcplink(sock, addr):
        print('Accept new connection from %s:%s...' % addr)
        while True:         # 和每个接入的客户端,进行多次数据通信
            data = sock.recv(1024)  # 接收客户端数据
            if not data or data.decode('utf-8') == 'exit':  # 如果客户端不发送数据或者发送了exit
                print('client disconnected.')
                break
            oper,filename = data.decode('utf-8').split()  # 对接收的数据按照空格分割
            if oper == 'get':
                m = hashlib.md5()
                if os.path.isfile(filename):
                    size = os.stat(filename).st_size   # 获取文件大小
                    print('Send size:',size)
                    sock.send(str(size).encode('utf-8'))  # 发送文件大小
                    recv = sock.recv(1024)              # 接收客户端确认信息(因为上下文两个send是连着的,所以为了防止粘包,接收一次信息)
                    f = open(filename,'rb')
                    for line in f:
                        sock.send(line)   #读取文件,发送给客户端
                        m.update(line)
                    # print('Send finished.',m.hexdigest())   # 打印md5的值
                    sock.send(m.hexdigest().encode('utf-8'))  # 把md5的值发送给客户端
        sock.close()
        print('Connection from %s:%s closed.' % addr)
    
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 监听端口:
    s.bind(('127.0.0.1', 9999))
    s.listen(3)
    print('Waiting for connection...')
    
    while True:
        # 接受一个新连接:
        sock, addr = s.accept()
        # 创建新线程来处理TCP连接:
        t = threading.Thread(target=tcplink, args=(sock, addr))
        t.start()

    客户端:

    import socket
    import hashlib
    
    # AF_INET 代表ipv4,SOCK_STREAM 代表TCP
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)     # 确定网络协议,生成对象
    s.connect(('127.0.0.1',9999)) # 连接服务器的地址和端口,元组的形式。
    while True:
        msg = input('>>:').strip()
        if len(msg) != 0:                  # 如果消息为空,会一直挂起,所以不能为空
            if msg =='exit':
                s.close()                     # 关闭连接
                print('Connection closed.')
                break
            s.send(msg.encode('utf-8'))       # 给服务器发送数据,必须是二进制的
            length = s.recv(1024)            # 首先接收服务器返回的将要接收的数据的长度信息。
            s.send(b'Ready to receive...')    # 发送接收确认命令
            length = int(length.decode('utf-8'))
            print('Recv size:', length)
            data_len = 0
            data_recv = b''
            # 新文件名
            fileName = msg.split()[-1].split('.')[0]
            fileExt =  msg.split()[-1].split('.')[-1]
            newFile = fileName+'-1.'+fileExt
            f = open(newFile,'wb')  # 打开文件,准备写入服务器发过来的文件
            m = hashlib.md5()
            while data_len < length:    # 已经接收的信息的长度,如果小于总长度
                size = length - data_len  
                if size > 1024:      # 如果剩下的信息长度大于1024,即不能一次性发完。
                    size = 1024
                else:        # 如果能一次性发完,就只收剩下的信息。目的是准确的接收文件的大小,把可能粘连的send的数据留给下一次recv
                    size = length-data_len
                data = s.recv(size)     # 从服务器接收数据
                f.write(data)
                m.update(data)
                data_len += len(data)
            f.close()
            print('recv_md5:',m.hexdigest())  # 打印返回的数据。
            recv = s.recv(1024)      # 接收下一次send的数据,即md5的值。
            print('orig_md5:',recv.decode())
  • 相关阅读:
    node
    github
    [模块] pdf转图片-pdf2image
    python 15 自定义模块 随机数 时间模块
    python 14 装饰器
    python 13 内置函数II 匿名函数 闭包
    python 12 生成器 列表推导式 内置函数I
    python 11 函数名 迭代器
    python 10 形参角度 名称空间 加载顺序
    python 09 函数参数初识
  • 原文地址:https://www.cnblogs.com/wztshine/p/12079510.html
Copyright © 2011-2022 走看看