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