Socket 服务器技术文档
1. 概述
本文档描述了一个基于 C++ 的简单 TCP socket 服务器的实现和用法。该服务器监听指定的端口,接受客户端毗连,读取客户端发送的消息,并向客户端发送一个固定的响应消息。
2. 情况要求
- C++ 编译器,支持 C++11 或更高版本
- POSIX 兼容操纵体系
- 支持 POSIX socket API 的库
3. 编译和运行
6. 后续改进
- 将服务器代码生存为一个名为 server.cpp 的文件。
- 利用以下下令编译代码:
- 运行服务器:
- 4. 服务器实现
4.1 头文件
- #include <iostream>
- #include <cstring>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <unistd.h>
复制代码 这些头文件分别用于输入输出流、字符串操纵、socket 编程、网络地点布局和 UNIX 标准函数。
4.2 定义端口号和缓冲区巨细
- #define PORT 8080
- #define BUFFER_SIZE 1024
复制代码 PORT 定义了服务器监听的端口号,BUFFER_SIZE 定义了用于读取和发送数据的缓冲区巨细。
4.3 主函数
主函数是程序的入口点,包含了服务器的主要逻辑。
4.4 创建 socket
- int server_fd, new_socket;
- server_fd = socket(AF_INET, SOCK_STREAM, 0);
复制代码 创建一个 socket 文件描述符 server_fd,用于监听客户端毗连。AF_INET 表示 IPv4 地点族,SOCK_STREAM 表示 TCP 流套接字。
4.5 绑定地点和端口
- struct sockaddr_in address;
- bind(server_fd, (struct sockaddr*)&address, sizeof(address));
复制代码 将 socket 绑定到本地地点和端口。
4.6 监听毗连
开始监听是否有客户端毗连。第二个参数 3 表示最大毗连数。
4.7 接受毗连
- new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen);
复制代码 接受客户端的毗连,并返回一个新的 socket 文件描述符 new_socket。
4.8 读取和发送数据
- read(new_socket, buffer, BUFFER_SIZE);
- send(new_socket, hello, strlen(hello), 0);
复制代码 从客户端读取数据到缓冲区,并向客户端发送固定的响应消息。
4.9 关闭 socket
关闭服务器 socket,开释资源。
5. 注意事项
- 本示例代码没有进行错误查抄和非常处置处罚,这在实际应用中是非常紧张的。
- 服务器只能同时处置处罚一个客户端毗连,不支持并发。
- 服务器在发送响应消息后立即关闭毗连,不进行持续通信。
- 添加错误查抄和非常处置处罚。
- 利用多线程或多进程支持并发毗连。
- 实现完备的客户端-服务器通信协议。
- #include <iostream>
- #include <cstring>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <unistd.h>
- #define PORT 8080
- #define BUFFER_SIZE 1024
- int main() { int server_fd, new_socket; struct sockaddr_in address; int opt = 1; int addrlen = sizeof(address); char buffer[BUFFER_SIZE] = {0}; const char* hello = "Hello from server"; // 创建 socket 文件描述符 if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("socket failed"); exit(EXIT_FAILURE); } // 绑定 socket 到地点和端口 address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); if (bind(server_fd, (struct sockaddr*)&address, sizeof(address))<0) { perror("bind failed"); exit(EXIT_FAILURE); } // 监听是否有客户端毗连 if (listen(server_fd, 3) < 0) { perror("listen"); exit(EXIT_FAILURE); } // 接受客户端的毗连 if ((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen))<0) { perror("accept"); exit(EXIT_FAILURE); } // 读取数据 read(new_socket, buffer, BUFFER_SIZE); std::cout << "Message from client: " << buffer << std::endl; // 发送数据 send(new_socket, hello, strlen(hello), 0); std::cout << "Hello message sent\n"; // 关闭 socket close(server_fd);
- return 0;}
复制代码 几个问题1.sockfd是什么?答:
在 socket 编程中,sockfd 是一个术语,通常用于指代一个 socket 的文件描述符。在 Unix-like 体系中,险些全部的 I/O 操纵都是通过文件描述符进行的,包括网络通信。文件描述符是一个非负整数,它是内核为了高效管理已打开的文件或其他 I/O 资源(如 socket、管道、设备等)而提供的一个抽象句柄。
当你创建一个 socket 时,体系会返回一个文件描述符,这个文件描述符就被称为 sockfd。之后,你就可以利用这个文件描述符来进行各种 socket 操纵,好比绑定地点(bind)、监听毗连(listen)、接受毗连(accept)、读取数据(read)、发送数据(write 或 send)、关闭 socket(close)等。
比方,在下面的代码中,socket 函数创建了一个新的 socket,并返回了一个文件描述符,这个描述符被存储在变量 sockfd 中:
- int sockfd = socket(AF_INET, SOCK_STREAM, 0);
复制代码 在这里,AF_INET 指定了地点族为 IPv4,SOCK_STREAM 指定了 socket 范例为 TCP 流套接字。如果 socket 调用成功,sockfd 将是一个有效的文件描述符,用于后续的 socket 操纵。如果调用失败,sockfd 将被设置为一个特定的错误值(通常是 -1),而且可以通过查看 errno 变量来获取失败的缘故原由。
我们可以用一个类比来通俗易懂地解释 sockfd。
想象一下,你的电脑是一个大型的邮局,而你想通过邮局发送和吸收信件。在邮局中,每个信箱都有一个唯一的编号,这个编号就像是文件描述符。当你创建一个 socket 时,就像是你在邮局申请了一个新的信箱,邮局会给你一个编号(即 sockfd),这样你就可以通过这个编号来发送和吸收信件了。
当你想发送一封信时,你会把信放入对应编号的信箱中,然后邮局会帮你把信发送出去。同样地,当你创建了一个 socket 并获得了 sockfd,你就可以利用这个 sockfd 来进行网络通信,好比发送数据(send)和吸收数据(recv)。
当你不再必要这个信箱时,你可以通知邮局回收这个信箱,这样其他人就可以利用这个编号了。在 socket 编程中,当你完成全部的通信使命后,你必要关闭 socket,开释 sockfd,这样体系就可以重新利用这个编号了。
以是,sockfd 就像是邮局信箱的编号,它资助你管理和操纵网络通信。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |