在这篇文章中,我将先简要介绍socket原理,然后给出一个利用Python实现的简单通信样例,最后通过跟踪系统调用来分析Python中socket函数与Linux系统调用的对应关系。
1.socket简介
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。下图为原理图:
2.简单通信样例
server端:
import socket import time s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind(('127.0.0.1', 12580)) s.listen(1) sock, addr = s.accept() buf = sock.recv(1024).decode() while True: print("client: " + buf) data = input("server: ") sock.send(data.encode()) if data == '#q#': time.sleep(1) break buf = sock.recv(1024).decode()
client端:
import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('127.0.0.1', 12580)) while True: try: data = input("client: ") s.send(data.encode()) buf = s.recv(1024).decode() if buf == '#q#': s.close() break else: print("server: " + buf) except: print("error") s.close() exit(-1)
运行结果:
3.对应关系跟踪
使用命令strace python3 server.py来跟踪所使用的系统调用,部分结果为:
stat("/home/xiaopeng/anaconda3/lib/python3.7/socket.py", {st_mode=S_IFREG|0664, st_size=27363, ...}) = 0
……
socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_IP) = 3
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
bind(3, {sa_family=AF_INET, sin_port=htons(12580), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
listen(3, 1) = 0
accept4(3, {sa_family=AF_INET, sin_port=htons(48408), sin_addr=inet_addr("127.0.0.1")}, [16], SOCK_CLOEXEC) = 4
recvfrom(4, "haha", 1024, 0, NULL, NULL) = 4
write(1, "client: haha\n", 13client: haha) = 13
我们可以看到python中相关socket函数是如何对应到Linux系统的socket系统调用的,归纳为下表:
python函数 | Linux Socket API |
socket.socket | int socket(int domain, int type, int protocol); |
bind | int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); |
connect | int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); |
listen | int listen(int sockfd, int backlog); |
accept | int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); |
send | ssize_t send(int sockfd, const void *buf, size_t len, int flags); |
recv | ssize_t recv(int sockfd, void *buf, size_t len, int flags); |
close | int close(int socketfd) |
参考资料:https://github.com/mengning/net