返回介绍

socket 编程

发布于 2024-09-21 14:54:08 字数 2668 浏览 0 评论 0 收藏 0

说到代理,那肯定会跟网络协议有关,包括(tcp, ip, http),网络中的进程需要通过 socket 来通信,socket 可以认为是操作系统抽象出来的一类接口,供使用者能够更加方便的与底层的网络协议打交道。

0x01

我们先来看看 tcp 的 socket 编程。

服务端

import socket
import threading

# AF_INET: 基于 IPV4 的网络通信 SOCK_STREAM: 基于 TCP 的流式 socket 通信
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 将套接字绑定到地址
s.bind(('127.0.0.1', 8888))
# 监听 TCP 传入连接
s.listen(5)


def handle_tcp(sock, addr):
print("new connection from %s:%s" % addr)
sock.send(b'Welcome!')

while True:
data = sock.recv(1024)
if not data:
break
sock.send(b'Hello, %s!' % data)
sock.close()


while True:
sock, addr = s.accept()
t = threading.Thread(target=handle_tcp, args=(sock, addr))
t.start()

客户端

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 8888))
print(s.recv(1024))

for data in [b'dog']:
s.send(data)
print(s.recv(1024))
s.close()

上面是个很简单的客户端和服务端的例子,服务器端用了线程,主要是为了能够同时处理多个请求。不然每次处理请求的时候整个程序就会处于阻塞状态。

通过 wireshark 捕获请求,可以看到客户端经过三次握手和服务端连接成功,接下来双方开始发送数据,发送完成后,四次挥手断开连接。

具体说下过程吧

  1. 首先服务器端初始化一个 socket 对象,将 socket 绑定到 (127.0.0.1, 8888) 这个地址上(bind),然后开始监听(listen),并阻塞在 accept 函数上,直到有连接过来。
  2. 客户端也初始化一个 socket 对象,调用 connect 和服务端建立连接。
  3. 服务端 accept 函数返回了一个新的 sock 套接字对象,传入到新线程中和客户端交互数据。
  4. 接下来就是 socket 的 recv 和 send 函数进行数据的交互。
  5. 最后 socket close 关闭套接字。

由于 tcp 传递的数据属于 stream, 也就是调用 recv 和 send 的次数都没有限制,对数据的发送和边界也没有限制。这个和下文的 udp 编程有区别,发送端每执行一次写操作,udp 模块就会将它封装成一个 udp 包发送,接收端也对每个 udp 包执行一次读操作,每次都得完整取出来,如果没有足够的应用缓冲区来读取 udp 数据包,则会被截断。

0x02

再简单看下 udp 的 socket 编程

服务端

import socket

# AF_INET: 基于 IPV4 的网络通信 SOCK_DGRAM: 基于 udp 的流式 socket 通信
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 将套接字绑定到地址
s.bind(('127.0.0.1', 8888))

while True:
data, addr = s.recvfrom(1024)
print('Received from %s:%s.' % addr)
s.sendto(b'Hello, %s!' % data, addr)

客户端

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

for data in [b'dog']:
s.sendto(data, ('127.0.0.1', 8888))
print(s.recv(1024))
s.close()

由于 udp 不需要建立连接,只需要知道对方的 IP 地址和端口号,就可以直接发数据包。但是,能不能到达就不知道了。所以客户端直接通过 sendto() 给服务器发数据,服务端调用 recvfrom() 就能拿到数据。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文