Socket 接口简介
Socket 套接字是由 BSD(加州大学伯克利分校软件研发中心)开发的一套独立于具体协议的网络编程接口,应用程序可以用这个接口进行网络通信。要注意:Socket 不是一套通信协议(HTTP,FTP 等是通信协议),而是编程的接口,即我们在程序中使用的网络函数。TCP/IP 网络编程底层就是使用 Socket 接口来通信,所以在学习 TCP/IP 编程之前必须知道 Socket 的接口使用方法。
Socket API 接口
基本的编程接口有:socket,bind,listen,accept,connect,send,recv 等,这些函数都很重要,下面来一一学习这些函数。
创建通信套接字:socket
socket 函数创建一个通信的端点,并返回一个指向该端点的文件描述符(Linux 下一切皆是文件):
#include <sys/types.h>
#include <sys/socket.h>
/*
* domain: 通信协议簇,例如 AF_INET, AF_UNIX...
* type: SOCK_STREAM, SOCK_DGRAM 等等
* protocol: 通常为 0
* return: 成功返回文件描述符,失败返回 -1,并设置 erron
*/
int socket(int domain, int type, int protocol);
例如服务器端创建一个用于接受客户端连接的 socket 的代码:
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == server_fd) {
perror("socket");
exit(1);
}
分配套接字名称:bind
当用 socket 函数创建套接字后,并没有为它分配 IP 地址和端口,我们还需要使用 bind 函数来将指定的 IP 和端口分配给已经创建的 socket:
#include <sys/types.h>
#include <sys/socket.h>
/*
* sockfd: socket 返回的文件描述符
* addr: 含有要绑定的 IP 和端口的地址结构指针
* addrlen: 第二个参数的大小,使用 sizeof 来计算
* return: 成功返回 0,失败返回 -1,并设置 erron
*/
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
其实第二个参数要注意,参数指定的是 struct sockaddr *
类型,一般不直接使用这个结构,这个类型在 Linux 上有许多的变种,例如 sockaddr_in 和 sockaddr_un,经常使用后面 2 个结构定义 IP 和端口信息,在 bind 是强制转换成 struct sockaddr *
类型:
// struct sockaddr_un myaddr;
struct sockaddr_in myaddr;
myaddr.sin_family = AF_INET;
// 接受任何 IP 地址的连接
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
// 指定连接端口为 8080
myaddr.sin_port = htons(8080);
if(bind(server_fd, (struct sockaddr *)&myaddr, sizeof(sockaddr_in)) == -1) {
perror("bind");
exit(1);
}
开始监听:listen
使用 listen 来建立一个监听客户端连接的队列:
#include <sys/types.h>
#include <sys/socket.h>
/*
* sockfd: 监听的 socket 描述符
* backlog: 建立的最大连接数
* return: 成功返回 0,失败返回 -1,并设置 erron
*/
int listen(int sockfd, int backlog);
例如创建一个可以监听 10 个客户端连接请求的队列:
if(listen(server_fd, 10) == -1) {
perror("listen");
exit(1);
}
接受连接请求:accept
网络编程的核心一步就是建立客户端和服务器端的连接,使用 accept 来建立 2 者的连接:
#include <sys/types.h>