yhw-miracle

网络编程

痛点就是起点 writed in

本文为痛点就是起点原创文章,可以随意转载,但需注明出处。

Socket

提及网络编程,就不得不提 Socket(套接字) 概念。Socket 是网络编程中的一个抽象概念,通常我们用一个 Socket 表示“打开一个网络链接”,把打开链接的目标计算机的 IP 地址和端口号,以及协议类型等信息存储到 Socket 里。

python 进行网络编程时,实际上是 python 程序本身的进程连接到服务器进程的通信端口进行通信,可以看作是两个进程间的通信。python 提供了两个基本的 Socket 模块实现网络编程,分别为 Socket 和 SocketServer。

  • Socket 提供了标准的 BSD Sockets API。
  • SocketServer 提供了服务器中心类,可以简化网络服务器的开发。

Socket 类型

Socket 格式为:socket(family, type[,protocal]),需要给定地址族、套接字类型、协议编号来创建 Socket。

Socket类型 描述
socket.AF_UNIX 只能用于单一的 Unix 系统进程间通信
socket.AF_INET 服务器之间网络通信
socket.AF_INET6 服务器之间 IPv6 网络通信
socket.SOCK_STREAM 流式 socket,用于 TCP
socket.SOCK_DGRAM 数据报式 socket,用于 UDP
socket.SOCK_RAM 原始套接字,普通的套接字无法处理 ICMP、IGMP 等网络报文,而 SOCK_RAM 可以;其次,SOCK_RAM 也可以处理特殊的 IPv4 报文;此外,利用原始套接字,可以通过 IP_HDRINCL 套接字选项由用户构造 IP 头
socket.SOCK_SEQPACKET 可靠的连续数据报服务
创建 TCP Socket socket(socket.AF_INET, socket.SOCK_STREAM)
创建 UDP Socket socket(socket.AF_INET, socket.SOCK_DGRAM)

Socket 函数

服务器 Socket 函数:

| Socket 函数 | 描述 | | —— | —— | | s.bind(address) | 将套接字绑定到地址,在 AF_INET 下,以元祖 (host, port) 的形式表示地址 | | s.listen(backlog) | 开始监听 TCP 传入连接。backlog 指定在拒绝连接之前,操作系统可以挂起的最大的连接数量。该值最小为1,大部分情况设为5就可以了 | | s.accept() | 接受 TCP 连接并返回 (conn, address) ,其中 conn 是新的套接字对象,可以用来接收和发送数据;address 是连接客户端的地址 |   客户端 Socket 函数:

Socket 函数 描述
s.connect(address) 连接到 address 处的套接字。一般 address 的格式为元祖 (host, port) ,如果连接出错,返回 socket.error 错误
s.connect_ex(address) 功能与 connect(address) 相同,但是连接成功返回 0,连接失败返回 errno 的值

公共 Socket 函数:

Socket 函数 描述
s.recv(bufsize[,flag]) 接收 TCP 套接字数据,数据以字符串形式返回
s.send(string[,flag]) 发送 TCP 套接字数据,返回发送数据的字节数
s.sendall(string[,flag]) 完整发送 TCP 套接字数据,成功返回 None,失败抛出异常
s.recvfrom(bufsize[,flag]) 接收 UDP 套接字数据,返回 (data, address)
s.sendto(string[,flag],address) 发送 UDP 套接字数据,返回发送数据的字节数

还有一些公共 Socket 函数,如:s.close(),s.getpeername(),s.getsockname(),s.setsockopt(level, optname, value),s.getsockopt(level, optname[,buflen]),s.settimeout(timeout),s.setblocking(flag) 等,这些函数一般可以见名知意,且使用频率较低,如果需要了解,都可以查询 API 获得。

TCP 编程

TCP 是一种面向连接的通信方式,连接可靠,通信双方以流的形式发送数据。主动发起连接的是客户端,被动响应的是服务端。服务端程序编写步骤如下。

  1. 创建 Socket,绑定 Socket 到本地 IP 与端口。
  2. 开始监听连接。
  3. 进入循环,不断连接客户端的连接请求。
  4. 接收传来的数据,并发送给对方数据(一般为确认收到)。
  5. 传输完毕后,关闭 Socket。
# coding:utf-8
import socket, threading, time


def dealClient(sock, addr):
    # 第四步: 接收传来的数据,并发送给对方数据
    print('Accept new connection from %s:%s' % addr)
    sock.send(b'Hello,I am server!')
    while True:
        data = sock.recv(1024)
        time.sleep(1)
        if not data or data.decode('utf-8') == 'exit':
            break
        print('--- > %s !' % data.decode('utf-8'))
        sock.send(('Loop_msg: %s!' % data.decode('utf-8')).encode('utf-8'))

    # 第五步: 关闭 Socket
    sock.close()
    print('Connection from %s:%s' % addr)


if __name__ == '__main__':
    # 第一步: 创建一个基于 IPV4 和 TCP 协议的 Socket
    # Socket 绑定的 IP(127.0.0.1 为本机 IP)与端口
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind(('127.0.0.1', 9999))

    # 第二步: 监听链接
    s.listen(5)
    print('waiting for connection ...')
    while True:
        # 第三步: 接收一个新连接
        sock, addr = s.accept()
        t = threading.Thread(target=dealClient, args=(sock, addr))
        t.start()

接下来,需要编写客户端程序,与服务端程序检修交互。客户端程序编写步骤如下。

  1. 创建 Socket,连接服务器地址。
  2. 连接后发送数据和接收数据。
  3. 传输完毕后,关闭 Socket。
# coding:utf-8
import socket

if __name__ == '__main__':
    # 初始化 Socket
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 连接目标的 IP 和端口
    s.connect(('127.0.0.1', 9999))

    # 接收消息
    print('--- > ' + s.recv(1024).decode('utf-8'))

    # 发送消息
    s.send(b'Hello,I am client!')
    print('--- > ' + s.recv(1024).decode('utf-8'))
    s.send(b'exit')

    # 关闭 Socket
    s.close()

UDP 编程

UDP 是面向无连接的通信协议,使用 UDP 协议时,无需建立连接,只需知道对方的 IP 地址和端口号,就可以直接发送数据包,并不关心数据能否安全到达目的端。虽然 UDP 传输数据不可靠,没有建立连接的过程,但是 UDP 传输比 TCP 传输速度快,对于传输要求不严格的数据,可以采用 UDP 协议传输,从而提高速度。

UDP 服务端程序编写步骤:

  1. 创建 Socket,绑定制定的 IP 地址和端口。
  2. 直接发送数据和接收数据。
  3. 传输完毕后,关闭 Socket。
# coding:utf-8

import socket

if __name__ == '__main__':
    # 创建 Socket ,绑定指定的 IP 和端口
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.bind(('127.0.0.2', 9999))
    print('Bind UDP on 127.0.0.2:9999 ...')

    while True:
        # 直接发送数据和接收数据
        data, addr = s.recvfrom(1024)
        print('Received from %s:%s.' % addr)
        s.sendto(b'Hello, %s!' % data, addr)

UDP 客户端程序编写步骤:

  1. 创建 Socket。
  2. 直接可以与服务端程序进行数据交互。
  3. 传输完毕后,关闭 Socket。
# coding:utf-8

import socket

if __name__ == '__main__':
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    for data in [b'hello', b'world']:
        # 发送数据
        s.sendto(data, ('127.0.0.2', 9999))
        # 接收数据
        print(s.recv(1024).decode('utf-8'))
    s.close()

python 网络编程 UDP TCP
知识总结

欢迎关注,我们一起进行认知迭代!


痛点就是起点

© 2016 - 2020 基于 jekyll | Github Pags | iconfont By yhw-miracle