zoukankan      html  css  js  c++  java
  • python网络编程(二):网络编程之socket与socketserver

      socket是操作系统中I/O系统延伸部分,支持TCP和UDP等网络通信协议,它使计算机之间(或其本身)的进程通信称为可能。socket中的socket()函数、recv()函数和send()函数,相当于文件操作中的open()函数、read()函数、write()函数。因此,soket使得操作系统能够以文件描述符的方式对网络数据进行操作。

    1、socket中udp通信

      服务端:

    import socket
    udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # ''表示自己电脑的任何一个ip(无线和有限同时连接或者电脑有不同的网卡(桥接),会有多个ip).
    # 绑定端口:写的是自己的ip和固定的端口,一般是写在sever端
    bindAddr = ('', 9001)
    udpSocket.bind(bindAddr)
    recvData = udpSocket.recvfrom(1024)
    # print(recvData)
    print(recvData[0].decode('gbk'))
    udpSocket.close()
    # recvData的格式:(data, ('ip', 端口)).它是一个元组,前面是数据,后面是一个包含ip和端口的元组.

      客户端:

    import socket
    # upd链接
    # SOCK_DGRAM:数据报套接字,主要用于UDP协议
    udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 关闭防火墙
    # 同一网段(局域网)下,主机的ip地址和端口号.
    sendAddr = ('127.0.0.1', 9001)
    # sendData = bytes(input('请输入要发送的数据:'), 'gbk')
    sendData = input('请输入要发送的数据:').encode('gbk')
    # 使用udp发送数据,每一次发送都需要写上接收方的ip地址和端口号
    udpSocket.sendto(sendData, sendAddr)
    # udpSocket.sendto(b'hahahaha', ('192.168.10.247', 8080))
    udpSocket.close()

    2、socket中的TCP通信

      服务端:

    import socket
    tcpServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    tcpServer.bind(('', 8899))
    tcpServer.listen(5)
    # tcp的三次握手,写进了这一句话当中
    tcpClient, addr = tcpServer.accept()
    # tcpServer.accept(),不需要写ip,可以接收多个客户端的。但事先要绑定端口和接入的客户端的数量
    # client 表示接入的新的客户端
    # clientInfo 表示接入的新的客户端的ip和端口port
    recvData = tcpClient.recv(1024)
    print('%s: %s' % (str(addr), recvData.decode('gbk')))
    sendData = input("请输入返回数据: ")
    tcpClient.send(sendData.encode("gbk"))
    # tcp的四次握手,写进了这一句话
    tcpClient.close()
    tcpServer.close()
    # tcpServer.accept():等待客户端的接入,自带堵塞功能:即必须接入客户端,然后往下执行
    # tcpClient.recv(1024): 也是堵塞,不输入数据就一直等待,不往下执行.
    # tcpServer创建了两个套接字,一个是Server,另一个是tcpClient.Server负责监听接入的Client,再为其创建专门的tcpClient进行通信.

      客户端:

    import socket
    tcpClient = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    serverAddr = ('127.0.0.1', 8899)
    # tcp的三次握手,写进了这一句话
    tcpClient.connect(serverAddr)
    sendData = input('请输入要发送的数据:')
    tcpClient.send(sendData.encode('gbk'))
    recvData = tcpClient.recv(1024)
    print('接收到的数据为:%s' % recvData.decode('gbk'))
    tcpClient.close()
    # 为什么用send而不是sendto?因为tcp连接是事先链接好(只需连接一次),以后只管发数据就ok了。
    # 而udp必须用sendto,是发一次数据,连接一次。每次发送必须要指定对方的ip和port。
    # 相同的道理,在tcpServer端,要写recv,而不是recvfrom来接收数据

    3、socket开启循环

      服务端:

    import socket
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind(('127.0.0.1', 9003))
    server.listen(5)
    while True:
        serverThisClient, addr = server.accept()
        while True:
            recvData = serverThisClient.recv(1024)
            if len(recvData) > 1:
                print('recv: %s' % recvData.decode('utf-8'))
                sendData = input('send: ')
                serverThisClient.send(sendData.encode('utf-8'))
            else:
                print('再见!')
                break
        serverThisClient.close()
    server.close()

      客户端:

    import socket
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect(('127.0.0.1', 9003))
    while True:
        data = input("send:")
        client.send(data.encode("utf-8"))
        recv = client.recv(1024)
        print("recv: %s" % recv.decode("utf-8"))
    client.close()

    4、socket多线程

      socket是自带阻塞的。一次只能接收和处理一个链接。如果一次接收多个连接,可以用多线程的方式实现。改写上面服务器的写法,客户端保持不变(可以启动多个client看看效果)。

    from threading import Thread
    import socket
    class Connect(object):
      """connect就是一个链接"""
    def __init__(self, conn, addr): self.conn = conn # 本次链接的conn self.addr = addr # 本次链接的ip地址和端口 self.bsize = 1024 self.before() try: self.handle() except: raise socket.SO_ERROR self.after() def handle(self): try: while True: recvData = self.conn.recv(self.bsize) print("recv: %s." % recvData.decode("utf-8")) sendData = input("send: ") self.conn.send(sendData.encode("utf-8")) except: self.conn.close() def before(self): print("Connected from: %s." % self.addr[0]) def after(self): print("Closed from %s." % self.addr[0]) def main(): tcpSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) tcpSocket.bind(('', 9003)) tcpSocket.listen(5) while True: conn, addr = tcpSocket.accept() Thread(target=Connect, args=(conn, addr)).start() tcpSocket.close() if __name__ == '__main__': main()

    5、使用自带的socketServer模块实现socket多线程

      上面已经实现了多线程的socket连接。python提供了socketServer来实现功能更全面的封装。对上面的服务端用socketServer进行重写。

    import socketserver
    class Server(socketserver.BaseRequestHandler):
        def handle(self):
            while True:
                recvData = self.request.recv(1024)
                print("recv: %s." % recvData.decode("utf-8"))
                sendData = input("send: ")
                self.request.send(sendData.encode("utf-8"))
    if __name__ == '__main__':
        server = socketserver.ThreadingTCPServer(("", 9003), Server)
        server.serve_forever()

    6、socketserver实现文件传输

      服务端:

      (文件地址:https://files.cnblogs.com/files/kuaizifeng/Python%E9%87%8D%E8%A6%81%E7%9A%84%E7%AC%AC%E4%B8%89%E6%96%B9%E5%BA%93.pdf.zip)

    import socketserver, struct
    class MyServer(socketserver.BaseRequestHandler):
        def handle(self):
            f = open("Python重要的第三方库.pdf.zip", mode="ab")
            size = self.request.recv(4)             # 只接收4个字节
            size = struct.unpack('i', size)[0]      # struct模块将python中的数据类型转换成C中的字节。第一次发数据大小,是int类型(struct用i表示),它在C中占4个字节
            print(size)                             # 如果recv接收不是4个字节,则会报错(粘包)
            length = 0
            while True:
                data = self.request.recv(1024)
                f.write(data)
                length += len(data)
                if len(data) < 1024:
                    f.close()
                    break
            if length == size:
                print("over.")
            else:
                print("error.")
    if __name__ == '__main__':
        server = socketserver.ThreadingTCPServer(("", 9009), MyServer)
        server.serve_forever()

      客户端:

    import socket, struct, os
    
    client = socket.socket()
    client.connect(("localhost", 9009))
    
    filepath= os.path.dirname(os.path.dirname(__file__))   # 定位这个文件路径
    file = os.path.join(filepath, "Python重要的第三方库.pdf.zip")
    f = open(file, mode="rb")
    count = 0
    size = os.path.getsize(file)
    size = struct.pack('i', size)
    client.send(size)
    print("size: {}.".format(size))
    while True:
        data = f.read(1024)
        client.send(data)
        count += 1
        if len(data) < 1024:
            break
        print("send: {}.".format(count))
    client.close()
  • 相关阅读:
    深度学习实战 Tricks
    Latex 琐碎
    Latex 琐碎
    数据网站(数据集的获取)、打分网站
    数据网站(数据集的获取)、打分网站
    matplotlib —— 添加文本信息(text)
    hdu 1506 Largest Rectangle in a Histogram
    poj2007
    OpenRisc-43-or1200的IF模块分析
    RHEL 6.4 安装svn和apache
  • 原文地址:https://www.cnblogs.com/kuaizifeng/p/9163339.html
Copyright © 2011-2022 走看看