Python网络编程-socket套接字

套接字对象(内置)方法

soket1

socket()模块函数

要创建套接字,必须用socket.socket()函数socket(socket_family,socket_type,protocol=0)其中,socket_family是AF_UNIX或AF_INET,socket_type是SOCK_STREAM(TCP)或SOCK_DGRAM(UTP)。protocal通常为0.

创建TCP服务器

通用的TCP服务器的一般伪代码

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

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

创建TCP服务器(代码)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from  socket import *
from time import ctime
ss = socket()
HOST = '' #表示可以使用任何可用的地址
PORT = 21567 #选择一个端口号 >1024 小于1024的端口号预留给了系统
BUFSIZE = 1024 #设置缓冲区的大小1KB 可调节
ADDR = (HOST,PORT) #元组 存放 IP 和端口号
tcpSerSock = socket(AF_INET,SOCK_STREAM) #分配TCP服务器套接字
tcpSerSock.bind(ADDR)     #将套接字绑定到服务器地址(主机名,端口号对)
tcpSerSock.listen(5)      #设置并启动TCP监听器 并传入连接请求的最大值(5只是个估计值,并不一定准确)
while True:
    print('waiting for connenct ...')
    #tcpCliSock 客户端连接套接字 addr 客户端 IP 和端口信息
    tcpCliSock,addr = tcpSerSock.accept() #被动等待客户端发送消息 
    print('...connect from :',addr)
    while True :
        data = tcpCliSock.recv(BUFSIZE) #接收 缓冲区中存储的客户端发过来的数据
        if not data :
            break
        tcpCliSock.send(bytes('[%s] %s' %(ctime(),data),'utf-8')) #将结果return 给客户端
    tcpCliSock.close() #关闭客户端
tcpSerSock.close() #关闭服务端 永远不会被执行。如果要在某条件下退出服务器,可以考虑使用close()

socket缓冲区BUFSIZ

每个 socket 被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区。

write()/send() 并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送到目标机器。一旦将数据写入到缓冲区,函数就可以成功返回,不管它们有没有到达目标机器,也不管它们何时被发送到网络,这些都是TCP协议负责的事情。

TCP协议独立于 write()/send() 函数,数据有可能刚被写入缓冲区就发送到网络,也可能在缓冲区中不断积压,多次写入的数据被一次性发送到网络,这取决于当时的网络情况、当前线程是否空闲等诸多因素,不由程序员控制。

read()/recv() 函数也是如此,也从输入缓冲区中读取数据,而不是直接从网络中读取。
TCP套接字的I/O缓冲区示意图
图:TCP套接字的I/O缓冲区示意图

这些I/O缓冲区特性可整理如下:
1. I/O缓冲区在每个TCP套接字中单独存在;
2. I/O缓冲区在创建套接字时自动生成;
3. 即使关闭套接字也会继续传送输出缓冲区中遗留的数据;
4. 关闭套接字将丢失输入缓冲区中的数据。

TCP套接字的阻塞模式

对于TCP套接字(默认情况下),当使用 write()/send() 发送数据时:
1. 首先会检查缓冲区,如果缓冲区的可用空间长度小于要发送的数据,那么 write()/send() 会被阻塞(暂停执行),直到缓冲区中的数据被发送到目标机器,腾出足够的空间,才唤醒 write()/send() 函数继续写入数据。
2. 如果TCP协议正在向网络发送数据,那么输出缓冲区会被锁定,不允许写入,write()/send() 也会被阻塞,直到数据发送完毕缓冲区解锁,write()/send() 才会被唤醒。
3. 如果要写入的数据大于缓冲区的最大长度,那么将分批写入。
4. 直到所有数据被写入缓冲区 write()/send() 才能返回。
当使用 read()/recv() 读取数据时:
1. 首先会检查缓冲区,如果缓冲区中有数据,那么就读取,否则函数会被阻塞,直到网络上有数据到来。
2. 如果要读取的数据长度小于缓冲区中的数据长度,那么就不能一次性将缓冲区中的所有数据读出,剩余数据将不断积压,直到有 read()/recv() 函数再次读取。
3. 直到读取到数据后 read()/recv() 函数才会返回,否则就一直被阻塞。

socket连接请求listen(*)

listen表示在拒绝新的连接之前,系统可以挂起的最大连接数量,这些连接还没有被accept方法接收到。

创建TCP客户端

通用的TCP客户端的一般伪代码

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

所有的套接字全部利用socket.socket()创建的。一旦客户端拥有了一个套接字,它就可以利用套接字的connect()方法直接创建一个到服务器的连接,当连接创建之后,他就可以参与到服务器的一个对话中。

创建TCP客户端(代码)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from socket import *
HOST = 'localhost'
PORT = 21567
BUFSIZE =1024
ADDR = (HOST,PORT)

tcpCliSock = socket(AF_INET,SOCK_STREAM) #创建套接字
tcpCliSock.connect(ADDR)    #连接套接字

while True:
    data = input('> ')  #输入内容
    if not data:
        break
    tcpCliSock.send(data.encode())  #发送输入内容
    data = tcpCliSock.recv(BUFSIZE) #接收服务端处理结果
    if not data:
        break
    print(data)
tcpCliSock.close()

多线程处理客户端请求

该例子没有实现多线程,仅是半双工模式,当建立一个连接且服务开始后,只有一个客户端在得到输入信息提示后进行会话,其他客户端处于等待状态。多线程可以使用socketserver模块,它支持客户端请求的线程和多线程处理。

参考文献:

TCP套接字
Socket

猜你喜欢

转载自blog.csdn.net/bug4pie/article/details/79533074