天天看点

Python3 网络编程——SOCKET编程SOCKET编程

SOCKET编程

socket(套接字): 应用程序通常通过”套接字”向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯。网络大多基于Socket通信。

通过IP+端口定位对方并发送消息的通信机制

分为UDP和TCP。

socket()函数

用 socket()函数来创建套接字,语法格式如下:

socket.socket([family[, type[, proto]]])

参数

family: 套接字家族可以使AF_UNIX或者AF_INET(ipv4协议族)

type: 套接字类型 。分为:面向连接的:SOCK_STREAM(使用TCP通信)和面向非连接:SOCK_DGRAM(使用UDP通信)

protocol: 一般不填默认为0.

Socket 对象(内建)方法

服务器端套接字:

s.bind() :绑定地址(host,port)到套接字, 在AF_INET下,以元组(host,port)的形式表示地址。

s.listen() :TCP监听。backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5。

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

客户端套接字:

s.connect(): 主动初始化TCP服务器连接。一般address的格式为元组(hostname,port)。

公共用途的套接字函数:

s.recv() :接收TCP数据,数据以字符串形式返回,bufsize指定要接收的最大数据量。

s.send() :发送TCP数据,将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。

s.recvfrom() :接收UDP数据,与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。

s.sendto(): 发送UDP数据,将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。

s.close() :关闭套接字。

UDP 编程

Server端流程 :

1. 建立socket,socket是负责具体通信的一个实例

2. 绑定,为创建的socket指派固定的端口和ip地址

3. 接受对方发送内容

4. 给对方发送反馈,此步骤为非必须步骤。

Client端流程:

1. 建立通信的socket 。

2. 发送内容到指定服务器 。

3. 接受服务器给定的反馈内容。

服务器案例:

# socket模块负责socket编程
import socket

# 模拟服务器的函数
def serverFunc():
    # 1. 建立socket
    # socket.AF_INET:使用ipv4协议族
    # socket.SOCK_DGRAM: 使用UDP通信
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # 2. 绑定ip和port
    # 127.0.0.1: 这个ip地址代表的是机器本身
    # 9999: 随手指定的端口号
    # 地址是一个tuple类型,(ip, port)
    addr = ("127.0.0.1",  )
    sock.bind( addr )


    # 接受对方消息
    # recvfrom接受的返回值是一个tuple,前一项表示数据,后一项表示地址
    # 参数的含义是缓冲区大小
    # rst = sock.recvfrom(500)
    data, addr = sock.recvfrom()

    print(data)

    # 发送过来的数据是bytes格式,必须通过解码才能得到str格式内容
    # decode默认参数是utf8
    text = data.decode()
    print(text)

    # 给对方返回的消息
    rsp = "欢迎访问"

    # 发送的数据需要编码成bytes格式,默认是utf8
    data = rsp.encode()
    sock.sendto(data, addr)


if __name__ == '__main__':
    print("Starting server.........")
    serverFunc()
    print("Ending server........")
           

客户端案例:

import socket

def clientFunc():

    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    text = "Hello World!"
    data = text.encode()

    # 发送
    sock.sendto(data,  ("127.0.0.1", ))
    data, addr  = sock.recvfrom()
    data = data.decode()
    print(data)

if __name__ == '__main__':
    clientFunc()
           

服务器程序要求永久运行,一般用死循环处理。

TCP编程

面向链接的传输,即每次传输之前需要先建立一个链接。

Server端的流程:

1.建立socket负责具体通信,这个socket其实只负责接受对方的请求,真正通信的是链接后重新建立的socket。

2. 绑定端口和地址。

3. 监听接入的访问socket。

4. 接受访问的socket,可以理解为建立了一个通讯的链接通路。

5. 接受对方的发送内容,利用接收到的socket接收内容。

6. 如果有必要,给对方发送反馈信息。

7. 关闭链接通路。

Client端流程:

1. 建立通信socket。

2. 链接对方,请求跟对方建立通路。

3. 发送内容到对方服务器。

4. 接受对方的反馈。

5. 关闭链接通路。

服务器案例:

import socket

def  tcp_srv():
    # 1. 建立socket负责具体通信。
    # 需要用到两个参数
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 2. 绑定端口和地址
    # 此地址信息是一个元组类型内容,分两部分:字符串(代表ip)+端口
    addr = ("127.0.0.1", )
    sock.bind(addr)

    # 3. 监听接入的访问socket
    sock.listen()

    while True:
        # 4. 接受访问的socket,即建立一个通讯的链接通路
        # accept返回的元组第一个元素赋值给skt,第二个赋值给addr
        skt,addr = sock.accept()

        # 5. 接受对方的发送内容
        # 500代表接收使用的buffersize
        msg = skt.recv()
        msg = msg.decode()
        rst = "Received msg: {0} from {1}".format(msg, addr)
        print(rst)
        # 6. 如果有必要,给对方发送反馈信息
        skt.send(rst.encode())

        # 7. 关闭链接通路
        skt.close()

if __name__ == "__main__":
    print("Starting tcp server.......")
    tcp_srv()
    print("Ending tcp server.......")
           

客户端案例:

import socket

def tcp_clt():
    # 1. 建立通信socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2. 链接对方,请求跟对方建立通路
    addr = ("127.0.0.1", )
    sock.connect(addr)
    # 3. 发送内容到对方服务器
    msg = "Hello World!"
    sock.send(msg.encode())
    # 4. 接受对方的反馈
    rst =  sock.recv()
    print(rst.decode())
    # 5. 关闭链接通路
    sock.close()


if __name__ == "__main__":
    tcp_clt()