一个hello/hi的简单的网络聊天程序和python Socket API与Linux Socket API之间的关系

1.Socket概述

套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。网络套接字是IP地址与端口的组合

套接字可以看成是两个网络应用程序进行通信时,各自通信连接中的一个端点。通信时,其中的一个网络应用程序将要传输的一段信息写入它所在主机的Socket中,该Socket通过网络接口卡的传输介质将这段信息发送给另一台主机的Socket中,使这段信息能传送到其他程序中。因此,两个应用程序之间的数据传输要通过套接字来完成。工作流程如下图所示:

一个hello/hi的简单的网络聊天程序和python Socket API与Linux Socket API之间的关系

Socket():创建套接字。

 
Bind():指定本地地址。在某个知名端口(Well-known Port)上操作的服务器进程必须要对系统指定本地端口,所以一旦创建了一个套接字,服务器就必须使用bind()系统调用为套接字建立一个本地地址。
 
Connect():将套接字连接到目的地址。客户机可以调用connect()为套接字绑定一个永久的目的地址,将它置于已连接状态。对数据流方式的套接字,必须在传输数据前,调用connect()构造一个与目的地的TCP连接,并在不能构造连接时返回一个差错代码。
 
Listen():设置等待连接状态。对于一个服务器的程序,当申请到套接字,并调用bind()与本地地址绑定后,就应该等待某个客户机的程序来要求连接。listen()就是把一个套接字设置为这种状态的函数。
 
Accept():接受连接请求。服务器进程使用系统调用socket,bind和listen创建一个套接字,将它绑定到知名的端口,并指定连接请求的队列长度。然后,服务器调用Accept进入等待状态,直到到达一个连接请求。
 
Send()/Receive():发送和接收数据 。在数据流方式中,一个连接建立以后,或者在数据报方式下,调用了Connect()进行了套接字与目的地址的绑定后,就可以调用Send()和Receive()函数进行数据传输。
 
Close():关闭套接字。
 
2.python网络聊天程序

直接上代码:

客户端:

import socket
import sys

# 创建一个socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 建立连接
s.connect((‘127.0.0.1‘, 3000))
while True:
    # 发送数据:
    try:
        data = input("客户端:")
        s.send(data.encode())
        buf = s.recv(1024).decode()
        if buf != ‘exit‘:
            print("服务端: " + buf)
    except:
        print("Dialogue Over")
        s.close()
        sys.exit(0)

服务端:

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((‘127.0.0.1‘, 3000))  # 监听端口
s.listen(1)  # 调用listen()方法开始监听端口,传入的参数指定等待连接的最大数量
sock, addr = s.accept()
buf = sock.recv(1024).decode()
while True:
    if buf != ‘exit‘:
        print("客户端: " + buf)
    data = input("服务端: ")
    sock.send(data.encode())
    if data == ‘exit‘:
        break
    buf = sock.recv(1024).decode()

这两个程序有这么几行,对应上面的工作流程说明:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM):

创建socket实现IPV4的通信(socket.AF_INET)并使用流式socket for TCP(socket.SOCK_STREAM)

s.bind((‘127.0.0.1‘, 3000)):

将地址(主机名(127.0.0.1)、端口号(3000)对)绑定到套接字上

s.connect((‘127.0.0.1‘, 3000))

连接到指定的服务端的socket上

s.listen(1):

调用listen()方法开始监听端口,传入的参数指定等待连接的最大数量,此处为1

sock, addr = s.accept() :

接受TCP连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。

sock.send(data.encode()):

发送TCP数据,将参数中的数据发送到连接的套接字。

buf = sock.recv(1024).decode():

接受TCP套接字的数据。数据以字符串形式返回,指定要接收的最大数据量为1024。

s.close():

关闭套接字。

程序运行结果如下:

客户端:

一个hello/hi的简单的网络聊天程序和python Socket API与Linux Socket API之间的关系

 服务端:

一个hello/hi的简单的网络聊天程序和python Socket API与Linux Socket API之间的关系

 注意要先启动Server再启动Client,否则会报错

3.python函数和Linux Socket API的对应关系

对应关系如下表:

python函数Linux Socket API
socket.socketint socket(int domain, int type, int protocol);
bindint bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
connectint connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
listenint listen(int sockfd, int backlog);
acceptint accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
sendssize_t send(int sockfd, const void *buf, size_t len, int flags);
recvssize_t recv(int sockfd, void *buf, size_t len, int flags);
closeint close(int socketfd)

可以通过strace python3 server.py命令跟踪这个程序所使用的系统调用

在输出的结果中有这么一段:

 一个hello/hi的简单的网络聊天程序和python Socket API与Linux Socket API之间的关系

 这个程序使用的系统调用对应上面的表格中的Linux Socket API

相关推荐