Linux Socket Programming
Ⅰ. Introduction
Socket Programming是POSIX标准的一部分,它实现了不同计算机进程之间的互相通信。尽管Socket API可以使用不同的网络协议,但本文的讨论仅限于Internet的事实标准:TCP/IP。
Ⅱ. Linux Socket Programming Basics
1.1 socket()
为了执行网络Socket I/O,一个进程首先要使用socket()初始化一个Socket Endpoint。与打开文件时返回的File Descriptor类似,socket()在成功时返回Socket Descriptor (sockfd)供其他接口访问Socket Endpoint。
#include <sys/socket.h>
int socket(int family, int type, int protocol);
常见的参数:
family | 说明 |
---|---|
AF_INET | IPv4协议 |
AF_INET6 | IPv6协议 |
type | 说明 |
---|---|
SOCK_STREAM | 字节流套接字 |
SOCK_DGRAM | 数据报套接字 |
SOCK_RAW | 原始套接字 |
protocol | 说明 |
---|---|
IPPROTO_TCP | TCP传输协议 |
IPPROTO_UDP | UDP传输协议 |
1.2 bind()
初始化Socket Endpoint的时候没有设置IP Address和Port,需要调用bind()将IP Address和端Port与Socket Endpoint绑定。如果一个Server/Client并没有调用bind()进行IP Address和Port的绑定,那么内核就会为其设置本机的IP Address并临时分配一个Port。这种行为一般仅适用于Client,而Server一般要暴露一个众所周知的Port。
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
1.3 connect()
Client调用connect()与Server建立连接。例如,如果是TCP Socket,那么connect()会触发3-way handshake。
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr* servaddr, socketlen_t addrlen);
1.4 listen()
listen()仅由TCP Server调用,它指示Linux Kernel此Socket Endpoint应该接受指向它的连接请求,第二个参数规定了Linux Kernel应该为该Socket Endpoint排队的最大连接数。
#include <sys/socket.h>
int listen(int socketfd, int backlog);
为了了解backlog参数,需要了解Linux Kernel为任何一个Listening Socket维护两个队列:
- 未完成的队列(incomplete connection queue)
- 已完成的队列(completed connection queue)
如下图所示:
1.5 accept()
accept()仅由TCP Server调用,它接受一个Listening Socket File Descriptor,并返回从completed connection queue中返回一个已完成的连接,使用Connected Socket File Descriptor表示,如果completed connection queue为空,那么进程进入睡眠。
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr* cliaddr, socklen_t* addrlen);
区分Listening Socket和Connected Socket非常重要,一个服务器通常仅仅创建一个Listening Socket,它在该服务器的生命周期内一直存在,之后Linux Kernel为每个已经连接的Client创建一个Connected Socket,当完成服务时,这个Connected Socket也就会被关闭了。
如果我们对Client的IP Address和Port不感兴趣,那么就将第二、三个参数设置为空指针。
1.6 close()
关闭一个Socket,这个接口和关闭文件的是同一个。
#include <unistd.h>
int close(int sockfd);