一 、Socket 套接字:通讯端点 简介

socket起源于Unix,而Unix/Linux基本哲学之一就是「一切皆文件」,对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)。

Socket 是任何一种计算机网路通讯中最基础的内容。Socket通讯一般用户C/S结构系统的网路通讯。

Socket 网路通讯是基于TCP(传输控制协议)或UDP(用户数据报协议)两种协议通讯,所以有 面向连接(TCP )与无连接(UDP ) 两种通讯方式。

Python 要创建TCP 套接字就得在创建的时候,指定套接字类型为SOCK_STREAM,它使用 TCP/IP通讯协议。

Python 要创建UDP 套接字就得在创建的时候,指定套接字类型为SOCK_DGRAM,它使用UDP/IP通讯协议。

其他关于 客户/伺服器 的知识这里不多讲。

二、socket 参数与方法简介

1.参数说明

创建服务端socket方法:socket(family, type, proto=0)

family 参数:地址簇

值可以是AF_UNIX ,AF_INET,AF_INET6,默认AF_INET;
AF_INET基于IPv4;
AF_INET6基于IPv4;
AF_UNIX 只能用于Unix系统之间通讯。

type参数:类型

值可以是SOCK_STREAM ,SOCK_DGRAM,SOCK_RAW,SOCK_RDM,SOCK_SEQPACKET ,默认值SOCK_STREAM;
SOCK_STREAM 流式socket 基于TCP 协议;
SOCK_DGRAM 数据报式socket 基于 UDP协议;
SOCK_RAW 原始套接字,普通的套接字无法处理ICMP、IGMP等网路报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
SOCK_RDM 是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
SOCK_SEQPACKET 可靠的连续数据包服务。

proto参数:协议

0  (默认)与特定的地址家族相关的协议,如果是 0 ,则系统就会根据地址格式和套接类别,自动选择一个合适的协议。

2. 方法简介

伺服器端套接字函数

socket.bind( tuple) 绑定地址(主机,埠号对)到套接字

socket.listen( n ) 开始TCP 监听, n表示最多允许n个连接同时连接进来

socket.accept() 被动接受TCP 客户的连接,(阻塞式)等待连接的到来

客户端套接字函数

socket.connect() 主动初始化TCP 伺服器连接

socket.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛异常

公共用途的套接字函数

socket.recv() 接收TCP 数据

socket.send() 发送TCP 数据

socket.sendall() 完整发送TCP 数据

socket.recvfrom() 接收UDP 数据

socket.sendto() 发送UDP 数据

socket.getpeername() 连接到当前套接字的远端的地址

socket.getsockname() 当前套接字的地址

socket.getsockopt() 返回指定套接字的参数

socket.setsockopt() 设置指定套接字的参数

socket.close() 关闭套接字

面向阻塞的套接字方法

socket.setblocking() 设置套接字的阻塞与非阻塞模式

socket.settimeout() 设置阻塞套接字操作的超时时间

socket.gettimeout() 得到阻塞套接字操作的超时时间

面向文件的套接字的函数

socket.fileno() 套接字的文件描述符

socket.makefile() 创建一个与该套接字关连的文件

三、创建TCP伺服器通讯端

服务端与客户端通讯流程图

服务端创建链接流程解析:

创建伺服器套接字(ss = socket())

把地址绑定到套接字上(ss.bind())

监听连接(ss.listen())

伺服器无限循环(inf_loop:)

接受客户的连接(cs = ss.accept())

通讯循环(comm_loop:)

对话(接收与发送)(cs.recv()/cs.send())

关闭客户套接字(cs.close())

关闭伺服器套接字(ss.close())(可选)

示例:创建一个能接收客户的消息,在消息前加一个时间戳后返回的TCP 伺服器。

socket_server.py

from socket import socket
from time import ctime

HOST =
PORT = 4444
BUFSIZ = 1024
ADDR = (HOST, PORT)

tcpSerSock = socket() # 创建伺服器套接字
tcpSerSock.bind(ADDR) # 把地址绑定到套接字上
tcpSerSock.listen() # 监听连接

while True: # 伺服器无限循环
print(等待连接...)
tcpCliSock, addr = tcpSerSock.accept() # 接受客户的连接
print(连接地址, addr)

while True: # 通讯循环
data = tcpCliSock.recv(BUFSIZ) # 接收TCP 数据
if not data:
break
tcpCliSock.send([%s] %s % (ctime(), data)) # 发送TCP 数据

tcpCliSock.close() # 关闭客户套接字
tcpSerSock.close() # 关闭伺服器套接字

四、创建TCP客户机通讯端

客服端创建链接流程解析:

创建客户套接字(cs = socket())

尝试连接伺服器(cs.connect()))

通讯循环(comm_loop:)

对话(接收与发送)(cs.send()/cs.recv())

关闭客户套接字(cs.close())

示例:与前面socket_server.py 进行通讯

socket_client.py

from socket import *

HOST = 127.0.0.1 # 伺服器连接地址
PORT = 4444 # 伺服器启用埠
BUFSIZ = 1024 # 缓冲区大小
ADDR = (HOST, PORT)

tcpClientSocket = socket(AF_INET, SOCK_STREAM) # 创建客户端连接
tcpClientSocket.connect(ADDR) # 绑定顶服务端地址

while True: # 通讯循环
sendData = bytes(input(> ), encoding="UTF-8") # 输入通讯内容,需要进行转换
if not sendData: # 无发送数据退出
break
tcpClientSocket.send(sendData) # 发送通讯内容
recvData = tcpClientSocket.recv(BUFSIZ) # 接收返回的通讯数据
if not recvData: # 无接收数据退出
break
print(recvData) # 列印返回的通讯数据

tcpClientSocket.close() # 关闭客服端连接

五、运行客户端与伺服器程序

  1. 先运行伺服器端程序 (win系统 cmd 窗口命令 python socket_server.py )。
  2. 再运行客户端程序 (win系统 重新开 cmd 窗口 命令 python socket_client.py )。
  3. 在客户端程序输入内容 Hi woodman 。

服务端输出内容:

等待连接...

连接 (127.0.0.1, 28520)等待连接...

客户端输出内容:

[Wed Oct 10 20:27:21 2018] Hi woodman

伺服器与客户端通讯流程

  1. 伺服器启动埠监听,监听埠连接qingq
  2. 客户端发送连接请求(TCP 3次握手)
  3. 当客户端连接上伺服器时,伺服器端显示『等待连接...』信息,并列印出连接地址。
  4. 在客户端接受服务的时候,伺服器又回去等待其它客户端的连接。
  5. 客户端发送数据,伺服器对数据进行处理,发送返回数据到客户端。
  6. 客户端接收到数据,对数据进行处理并列印数据。
  7. 客户端关闭连接,伺服器关闭与客户端连接,继续等待其他客户端的连接。(TCP 四次分手)

推荐阅读:

相关文章