Socket 编程

作者: 全栈coder | 来源:发表于2018-01-21 00:47 被阅读101次

    Socket 即套接字,是计算机网络数据结构,它用于进程之间的通信。

    想要理解socket, 涉及到的知识点有:TCP UDP 进程 端口 客户/服务器模式
    参考链接 : socket编程到底是什么?

    套接字有两种类型:面向连接和无连接。与之对应的传输层协议为TCP和UDP,至于啥叫面向连接啥叫无连接,建议看下计算机网络教材的传输层那一章。

    Python 中的网络编程

    既然你知道了关于客户端/服务器架构,套接字和网络方面的基础知识,接下来我们将这些概念运用到Python中。本文使用的主要模块就是socket模块,在这个模块中可以找到socket函数,该函数用于创建套接字对象。套接字也有自己的方法集,这些方法可以实现基于套接字的网络通信。

    socket()模块函数

    要创建套接字,必须使用 socket.socket()函数,它的一般语法如下。

       socket(socket_family, socket_type, protocol=0)
    

    其中,socket_family是AF_UNIX或AF_INET,socket_typeSOCK_STREAMSOCK_DGRAMprotocol 通常省略,默认为0。
    所以为了创建TCP/IP套接字,可以用下面的方式调用socket.socket()

       tcpSock = socket.socket(socket.AF_INET,  socket.STREAM)
    

    同样,为了创建UDP/IP套接字,需要执行如下语句。

       ucpSock = socket.socket(socket.AF_INET,  socket.DGRAM)
    

    一旦有了一个套接字对象,那么可以使用套接字对象的方法将可以进行进一步的交互。

    创建 TCP 服务器

    首先,我们将展现创建通过TCP服务器的一般伪代码,然后对这些代码的含义进行一般性的描述。需要记住的是,这仅仅是设计服务器的一种方式。一旦熟悉了服务器设计,那么你将能够按照自己的要求修改下面的伪代码来进行操作服务器。

             ss = socket()            #创建服务器套接字
             ss.bind()                #套接字和地址绑定
             ss.listen()              #监听连接
             inf_loop:                #服务器无限循环
                   cs = ss.accept()   #接受客户端的连接
                   comm_loop:         #通信循环
                       cs.recv()/cs.send()  #对话(接受/发送)
                   cs.close()         # 关闭客户端套接字
             ss.close()               #关闭服务器套接字(可选)
    
    

    所有套接字都是通过使用socket.socket()函数来创建的。因为服务器需要占用一个端口并等待客户端的请求,所以它们必须绑定到一个本地地址,因为TCP是一种面向连接的通信系统,所以在TCP服务器开始操作之前,必须安装一些基础设施。特别地,TCP服务器必须监听传入的连接。一旦这个安装过程完成之后,服务器就可以开始它的无限循环。

    调用accept()函数之后,就开启了一个简单的单线程服务器,它会等待客户端的连接。默认情况下,accept()是阻塞的,这意味着执行将被暂停,直到一个连接到达。另外套接字也确实支持非阻塞模式,可以参考文档或者操作系统教材,了解有关为什么以及如何使用非阻塞套接字的细节。

    一旦服务器接受了一个连接,就会返回一个独立的客户端套接字,用来与即将到来的消息进行交换,服务器会创建一个新的通信端口来与客户端进行通信,再次空出主要的端口,以使其能够接受新的客户端连接。

    一旦创建了临时套接字,通信就可以开始,通过使用这个新的套接字,客户端与服务器就可以开始参与发送和接收新的对话中,直到连接终止。当一方关闭连接或者向对方法弄一个空字符串时,通常就会关闭连接。

    在代码中,一个客户端连接关闭后,服务器就会等待另一个客户端的连接,最后一行代码是可选的,在这里关闭了服务器套接字。其实,这种情况永远也不会碰到,因为服务器应该在一个无限循环中运行。

    示例代码: 它是一个TCP服务器程序,它接收客户端发送的数据字符串,并将其打上时间戳,并返回给客户端

    from socket import *
    from time import ctime
    
    HOST = ''
    PORT = 21567
    BUFSIZ = 1024
    ADDR = (HOST,PORT)
    
    tcpSerSock = socket(AF_INET, SOCK_STREAM)
    tcpSerSock.bind(ADDR)
    tcpSerSock.listen(5)
    
    while True:
        print('等待连接中。。。')
        tcpCliSock, addr = tcpSerSock.accept()
        print('。。。连接来自:', addr)
    
        while True:
            data = tcpCliSock.recv(BUFSIZ).decode()
            if not data:
                break
            tcpCliSock.send('[%s] %s' % (ctime(), data)).encode()
    
    
        tcpCliSock.close()
    
    tcpSerSock.close()
    

    创建TCP客户端

    创建客户端比服务器要简单的多。与对TCP服务器的描述类似,本节将先给出附带解释的伪代码,然后揭示真相。

            cs = socket()              #创建客户端套接字
            cs.connect()               #尝试连接服务器
            comm_loop:                 #通信循环
                cs.send()/cs.recv()    #对话(发送/接收)
            cs.close()                 #关闭客户端套接字
    

    正如前面提到的,所有的套接字都是利用socket.socket()创建的。然而,一旦客户端拥有了一个套接字,它就可以利用套接字的connect()方法直接创建一个到服务器的连接。当连接建立之后,它就可以参与到与服务器的一个对话中。最后,一旦客户端完成了它的事务,它就可以关闭套接字,终止此次连接。

    示例代码: 这个脚本连接到服务器,并以逐行数据的形式提示用户。服务器则返回加了时间戳的相同数据,这些数据最终会通过客户端代码呈现
    给用户。

    from socket import *
    HOST = '127.0.0.1'
    PORT = 21576
    BUFSIZ = 1024
    ADDR = (HOST,PORT)
    
    tcpCliSock = socket(AF_INET, SOCK_STREAM)
    tcpCliSock.connect(ADDR)
    
    while True:
        data = input('> ')
        if not data:
            break
        tcpCliSock.send(data)
        data = tcpCliSock.recv(BUFSIZ)
        if not data:
            break
        print(data.decode('utf-8'))
    
    tcpCliSock.close()
    

    执行TCP服务器和客户端

    关于这个简单的网络应用程序,有趣的一点是我们不仅展示了数据是如何从客户端到达服务器,并最后返回客户端;而且使用服务器作为一种“时间服务器”,因为我们接收到的时间戳完全来自服务器。

    相关文章

      网友评论

        本文标题:Socket 编程

        本文链接:https://www.haomeiwen.com/subject/fylxaxtx.html