文章参考socket教程及《Linux高性能服务器编程》
采用int socket(int domain, int type, int protocal)
函数创建一个套接字;
其中第一个参数domain指定协议族(IPv4/IPv6);
第二个参数type指定服务类型(SOCK_STREAM/SOCK_UGRAM分别对应TCP和UDP);
第三个参数一般默认为0。
#include
#include
int main()
{
// IPv4/TCP协议的socket
int server_socket = socket(PF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
perror("socket create error");
}
printf("socket is %d\n", server_socket);
return 0;
}
在步骤1中仅仅创建了基于IPv4及TCP协议的socket,但并没有指定该socket的地址,也即没有命名。这里采用int bind(int sockfd, const stuct sockaddr *my_addr, socklen_t addrlen)
函数来给1中创建的socket绑定一个socket地址;
其中第一个参数sockfd表示socket文件的描述符,也即步骤1中返回的server_socket;
第二个参数表示socket所要绑定的地址,是一个结构体;
第三个参数表示socket地址的长度,也即sizeof(my_addr)。
#include
#include // exit
#include
#include // sockaddr_in
#include
int main(int argc, char *argv[])
{
const char *server_ip = "127.0.0.1"; // IP地址字符串
int server_port = 0x1234; // 端口号
int server_socket = socket(PF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
perror("socket create error");
exit(1);
}
printf("socket is %d\n", server_socket);
struct sockaddr_in address;
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET; // IPv4
address.sin_port = htons(server_port); // 服务器端口号,转换为网络序
address.sin_addr.s_addr = inet_addr(server_ip);
// 绑定server_socket到address上
if (bind(server_socket, (struct sockaddr*)&address, sizeof(address)) == -1) {
perror("bind error");
exit(1);
}
printf("bind ok\n");
return 0;
}
创建完socket并绑定地址后,socket进入监听状态,使用int listen(int sockfd, int backlog)
函数创建一个监听队列以存放待处理的客户连接,将套接字sockfd指定为被监听的socket;
其中第一个参数sockfd为socket文件描述符;
第二个参数表示内核监听队列的最大长度;
成功返回0,失败返回-1。
#include
#include
#include
#include // sockaddr_in
#include
int main()
{
const char *server_ip = "127.0.0.1"; // IP地址字符串
int server_port = 0x1234; // 端口号
int server_socket = socket(PF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
perror("socket create error");
exit(1);
}
printf("socket is %d\n", server_socket);
struct sockaddr_in address;
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET; // IPv4
address.sin_port = htons(server_port); // 服务器端口号,转换为网络序
address.sin_addr.s_addr = inet_addr(server_ip);
// 绑定server_socket到address上
if (bind(server_socket, (struct sockaddr*)&address, sizeof(address)) == -1) {
perror("bind error");
exit(1);
}
printf("bind ok\n");
// 监听server_socket
if (listen(server_socket, 5) == -1) {
perror("listen error");
exit(1);
}
printf("listen ok\n");
return 0;
}
当服务器端socket创建完成后,就可以接受来自客户端的连接请求,调用int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
函数;
第一个参数sockfd表示listen指定的监听socket;
第二个参数addr表示客户端的地址;
第三个参数addrlen表示客户端地址的长度;
成功返回一个新的连接socket,该socket唯一标示了接受的新连接,后续双方可以利用已连接套接字进行通信;失败返回-1。
#include
#include
#include
#include // sockaddr_in
#include
int main()
{
const char *server_ip = "127.0.0.1"; // IP地址字符串
int server_port = 0x1234; // 端口号
int server_socket = socket(PF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
perror("socket create error");
exit(1);
}
printf("socket is %d\n", server_socket);
struct sockaddr_in address;
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET; // IPv4
address.sin_port = htons(server_port); // 服务器端口号,转换为网络序
address.sin_addr.s_addr = inet_addr(server_ip);
// 绑定server_socket到address上
if (bind(server_socket, (struct sockaddr*)&address, sizeof(address)) == -1) {
perror("bind error");
exit(1);
}
printf("bind ok\n");
// 监听server_socket
if (listen(server_socket, 5) == -1) {
perror("listen error");
exit(1);
}
printf("listen ok\n");
// 客户机地址
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
printf("等待连接中...\n");
int connfd = accept(server_socket, (struct sockaddr*)&client_addr, &client_addr_len);
if (connfd == -1) {
perror("accept error");
exit(1);
}
printf("accept ok\n");
return 0;
}
当服务器端做好接受连接的准备之后,客户端就可以主动请求连接了,这里采用int connect(int sockfd, const struct sockaddr *server_addr, socklen_t *addrlen)
函数;
第一个参数sockfd表示socket文件描述符;
第二个参数server_addr表示服务器端的地址;
第三个参数addrlen表示服务器端地址长度;
成功返回0,客户端利用connect函数连接服务端,如果连接成功后,其第一个参数sockfd就唯一标示这个连接;失败返回-1。