#include
#include
#include
#include
#include
using namespace std;
int main() {
int sockfd;
struct sockaddr_in server_addr;
char buffer[1024];
int n;
// 创建socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket error");
exit(1);
}
// 设置服务器地址信息
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
bzero(&(server_addr.sin_zero), 8);
// 连接服务器
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) < 0) {
perror("connect error");
exit(1);
}
// 发送数据
strcpy(buffer, "Hello, world!");
n = send(sockfd, buffer, strlen(buffer), 0);
if (n < 0) {
perror("send error");
exit(1);
}
// 接收数据
n = recv(sockfd, buffer, 1024, 0);
if (n < 0) {
perror("recv error");
exit(1);
}
cout << "Received message: " << buffer << endl;
// 关闭socket连接
close(sockfd);
return 0;
}
以上是客户端代码
#include
#include
#include
#include
#include
#include
#include
#include /* 多线程需要引入这个头文件。C++标准库提供了std::thread这个线程类,它允许在C++中编写多线程程序。使用std::thread需要包含头文件。在C++11及以后的标准中,std::thread已经被定义在头文件中。如果你的编译器支持C++11或者更新的版本,你可以直接使用std::thread。如果你的编译器只支持C++98,你可能需要自己定义std::thread,或者使用第三方库提供的线程类。注意,使用多线程编程需要谨慎处理线程同步和数据共享问题,以避免出现竞态条件和死锁等问题。*/
using namespace std;
void handle_client(int client_sock) {
char buffer[1024];
int n;
// 接收客户端发来的数据
n = recv(client_sock, buffer, 1024, 0);
if (n < 0) {
perror("recv error");
exit(1);
}
cout << "Received message from client: " << buffer << endl;
// 发送响应给客户端
strcpy(buffer, "Hello from server!");
n = send(client_sock, buffer, strlen(buffer), 0);
if (n < 0) {
perror("send error");
exit(1);
}
}
int main() {
int server_sock, client_sock;
struct sockaddr_in server_addr, client_addr;
socklen_t client_len = sizeof(struct sockaddr_in);
int n;
// 创建socket
server_sock = socket(AF_INET, SOCK_STREAM, 0);
if (server_sock < 0) {
perror("socket error");
exit(1);
}
// 设置服务器地址信息
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero), 8);
// 绑定socket到指定地址和端口号上,并监听连接请求
if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) < 0) {
perror("bind error");
exit(1);
}
if (listen(server_sock, 5) < 0) {
perror("listen error");
exit(1);
}
cout << "Server is listening on port 8080..." << endl;
// 接受客户端的连接请求,并创建新的socket用于与客户端进行通信
client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_len);
if (client_sock < 0) {
perror("accept error");
exit(1);
}
cout << "Client connected from " << inet_ntoa(client_addr.sin_addr) << endl;
/* 使用多线程处理客户端的请求,这里使用C++标准库中的std::thread类来创建线程。注意,C++标准库中的std::thread需要C++11或更高版本的支持。如果你的编译器只支持C++98,你可能需要使用第三方库提供的线程类。这里使用std::thread来创建一个新的线程来处理客户端的请求。线程函数是handle_client,它接受一个整数参数表示客户端的socket。在线程函数中,我们使用recv函数从客户端接收数据,并使用send函数发送响应。处理完请求后,线程结束。在主线程中,我们等待客户端的连接请求,并创建新的socket和线程来处理请求。这样,服务器就可以同时处理多个客户端的请求了。注意,使用多线程编程需要谨慎处理线程同步和数据共享问题,以避免出现竞态条件和死锁等问题。你可以使用互斥锁(mutex)来保护共享数据,避免多个线程同时访问和修改同一份数据,从而引发问题。同时,也可以使用条件变量等同步机制来协调不同线程之间的操作顺序和条件。这样可以确保程序正确运行,并避免出现多线程编程中的常见问题。另外,记得在程序结束时关闭socket和释放资源。你可以使用close函数来关闭socket,并使用std::thread的析构函数来等待线程结束并释放相关资源。这样可以确保程序正常退出,并避免资源泄漏等问题。希望这个示例代码能帮助你理解TCP服务器的基本结构和实现方式。你可以根据自己的需求进行修改和扩展,实现更复杂的功能和更好的性能。记得在实际应用中考虑安全性和错误处理等方面的问题,以确保程序的稳定性和可靠性。*/
// 等待客户端的连接请求,并创建新的socket和线程来处理请求
while (true) {
client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_len);
if (client_sock < 0) {
perror("accept error");
exit(1);
}
cout << "Client connected from " << inet_ntoa(client_addr.sin_addr) << endl;
// 创建新的线程来处理客户端的请求
thread t(handle_client, client_sock);
t.detach(); // 让线程在后台运行,并自动管理线程的生命周期
}
/* 在主线程中等待客户端的连接请求,并创建新的socket和线程来处理请求。注意,这里使用了无限循环来不断等待连接请求,因此需要在程序结束时手动退出循环。*/
// 退出循环
cout << "Server is shutting down..." << endl;
break;
}
// 关闭服务器socket
close(server_sock);
// 等待所有线程结束
// 这里使用了std::thread的join方法来等待所有线程结束。join方法会阻塞当前线程,直到调用该方法的线程结束。通过循环调用join方法,可以等待所有线程结束。
cout << "Waiting for threads to finish..." << endl;
for (auto& th : threads) {
th.join();
}
cout << "All threads finished." << endl;
// 程序结束
return 0;
}