Skip to content

Socket

UDP通信

可以使用python里面的socket模块进行创建一个socket

python
import socket
socket.socket(AddressFamily, Type)

AddressFamily: AF_INET用于Internet进程里面的通讯, AF_UNIX用于同一台机器的通信

Type: 实际使用的协议, SOCK_STREAM流式套接字, 一般使用的是TCP, SOCK_DGRAM, 数据套接字, 一般用UDP

python
import socket

if __name__ == "__main__":
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(("www.baidu.com", 80))
    s.send(b"GET / HTTP/1.1\r\nHost: www.baidu.com\r\nConnection: close\r\n\r\n")
    buffer = []
    while True:
        d = s.recv(1024)
        if d:
            buffer.append(d)
        else:
            break
    data = b"".join(buffer)
    s.close()
    # 分离header和html
    header, html = data.split(b"\r\n\r\n", 1)
    print(header.decode("utf-8"))
    with open("baidu.html", "wb") as f:
        f.write(html)
    
    s.close()

函数

sendto发送信息

python
socket.sendto(bytes, address)¶
python
import socket

if __name__ == "__main__":
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    dest_addr = ("192.168.65.1", 8080)
    s.sendto(b"GET / HTTP/1.1\r\nHost: www.baidu.com\r\nConnection: close\r\n\r\n", dest_addr)

    s.close()

这一个直接发送的时候使用的是UDP, 在发送的时候这一个数据必须是bytes类型的, 发送的时候也可以使用一个字符串.encode('utf-8')进行编码, 获取的数据使用.decode("utf-8")进行解码

image-20240510221308398

发送数据的时候会使用一个随机的端口, 每一次程序里面只会申请一次端口

recvfrom接收udp数据

python
socket.recvfrom(bufsize[, flags])
python
import socket

if __name__ == "__main__":
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    dest_addr = ("192.168.65.1", 8080)
    s.sendto(b"GET /v1/images/search HTTP/1.1\r\nHost: www.baidu.com\r\nConnection: close\r\n\r\n", dest_addr)
    data, addr = s.recvfrom(1024)
    print(data.decode())
    print(addr)
    s.close()
bash
PS E:\JHY\python\2024-5-10-internet> python -u "e:\JHY\python\2024-5-10-internet\main.py"
hello
('192.168.65.1', 8080)

使用阻塞的方式进行获取数据, 接收的数据是一个元组, 里面分别的是获取的数据以及这一个数据的来源

See the Unix manual page recv(2) for the meaning of the optional argument flags; it defaults to zero. (The format of address depends on the address family — see above.)

bind绑定端口

python
socket.bind(address)

参数是一个元组, 第一个是元素ip字符串, 第二个元素是端口, 这一个ip可以为空, 会使用本机的ip

python
s.bind(("", 11451))

这一个绑定的时候需要在发送信息前面, 否则有一个自动绑定的端口, 不能再进行绑定

非阻塞

python
# 设置套接字为阻塞或非阻塞模式:如果 flag 为 false,则将套接字设置为非阻塞,否则设置为阻塞。
# socket.setblocking(flag)
# 如果value赋为 0,则套接字将处于非阻塞模式。如果指定为 None,则套接字将处于阻塞模式。
# socket.settimeout(value)
# 阻塞
sock.setblocking(True)
sock.settimeout(None)
# 非阻塞
sock.setblocking(False)
sock.settimeout(0.0)

UDP广播

发送给这一个局域网里面的每一个电脑的某一个端口发送一个数据

python
if __name__ == "__main__":
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 设置广播选项
    s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    # 广播地址
    dest_info = ('<broadcast>', 11451)
    while True:
        data = input("请输入要广播的内容:")
        s.sendto(data.encode(), dest_info)

主机号是255的是广播地址

TCP通信

  • 客户端
  1. 建立套接字
  2. 连接对方, connect
  3. 发送数据, send
  4. 接收数据, recv
  5. 关闭套接字, close
  • 服务器
  1. 建立TCP套接字
  2. 绑定ip以及端口, bind
  3. 等待连接, listen
  4. 接收连接, accept
  5. 发送接收数据, recv/send
  6. 关闭连接close
python
import socket

if __name__ == "__main__":
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 建立连接
    s.connect(("192.168.65.1", 11451))
    while True:
        data = input("请输入要发送的数据:")
        s.send(data.encode('gbk'))
        if data == "exit":
            break

    s.close()
    print("连接已关闭")

函数

send发送

recv接收

python
ret = s.recv(1024)
print(ret.decode('gbk'))

这时候获取的数据只有对方发送的数据

accept等待连接

python
import socket

if __name__ == "__main__":
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind(("127.0.0.1", 11451))
    s.listen(5)
    print("服务器启动成功")
    while True:
        client, addr = s.accept()
        print("连接地址:", addr)
        while True:
            data = client.recv(1024)
            if data == b"exit":
                break
            print(data.decode())
            client.send("已收到".encode())
        client.close()
        print("连接已关闭")

服务连接的时候需要等待客户端断开连接, 否则会出现错误, 四次挥手的TIME_WAIT阶段会由服务器进行, 这一个资源需要等待2msl

对方发送的数据是一个空字符串的时候, 这一个连接是中断了