【发布时间】:2018-01-01 21:19:01
【问题描述】:
我正在尝试实现自己的服务器和客户端,它们使用套接字来发送和接收数据。但是我在实现多线程方面遇到了一些问题。 我的 server.cpp:
#include <iostream>
#include <netinet/in.h>
#include <cstring>
#include <arpa/inet.h>
#include <unistd.h>
#include <thread>
using namespace std;
void connection_handler(int socket) {
char client_message[256];
memset(&client_message, 0, 256);
size_t message_size = 0;
while ((message_size = recv(socket, client_message, sizeof(client_message) - 1, 0)) > 0) {
client_message[message_size] = '\0';
cout << "[Server] Client message accepted" << endl;
cout << "[Server] Client message: " << client_message << endl;
if (write(socket, client_message, message_size) == -1) {
cout << "[Client] Message sending failed" << endl;
return;
}
cout << "[Server] Message sent to client" << endl << endl;
cout << "============================" << endl << endl;
cout.flush();
memset(&client_message, 0, 256);
}
}
int main() {
unsigned short int PORT = 8080;
int listener, client_socket;
socklen_t client_len;
struct sockaddr_in server_address{};
memset(&server_address, 0, sizeof(server_address));
listener = socket(AF_INET, SOCK_STREAM, 0);
server_address.sin_family = AF_INET;
server_address.sin_port = htons(PORT);
if (inet_aton("127.0.0.1", &server_address.sin_addr) == 0) {
cout << "[Server] Invalid IP address" << endl;
return -1;
}
if (bind(listener, (struct sockaddr*) &server_address, sizeof(server_address)) == -1) {
cout << "[Server] Binding failed" << endl;
return -1;
}
cout << "[Server] All setting are done" << endl;
cout << "[Server] Server enabled" << endl;
if (listen(listener, 100) == -1) {
cout << "[Server] Listening failed" << endl;
return -1;
}
cout << "[Server] Waiting for connection..." << endl;
for (; ;) {
client_socket = accept(listener, (struct sockaddr*) &server_address, &client_len);
cout << "[Server] Connection accepted" << endl << endl;
cout << "----------------------------" << endl << endl;
int new_socket = client_socket;
thread handling_thread(connection_handler, new_socket);
handling_thread.detach();
}
}
我的client.cpp:
#include <iostream>
#include <netinet/in.h>
#include <cstring>
#include <arpa/inet.h>
#include <unistd.h>
using namespace std;
int main() {
unsigned short int PORT = 8080;
int sockfd;
char buffer[256] = {0};
struct sockaddr_in server_address{};
sockfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&server_address, '0', sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(PORT);
server_address.sin_addr.s_addr = INADDR_ANY;
if (connect(sockfd, (struct sockaddr*) &server_address, sizeof(server_address)) < 0) {
cout << "[Client] Connection failed" << endl;
return -1;
}
cout << "[Client] All setting are done" << endl;
cout << "[Client] Succefully connected to server" << endl << endl;
cout << "----------------------------" << endl << endl;
while (true) {
string client_request;
cout << "[Client] Enter a message: ";
getline(cin, client_request);
if (client_request == "-1") {
write(sockfd, client_request.c_str(), client_request.size());
close(sockfd);
cout << endl << "[Client] Client exited" << endl;
return 0;
}
if (write(sockfd, client_request.c_str(), client_request.size()) == -1) {
cout << "[Client] Message sending failed" << endl;
}
cout << "[Client] Message sent to server" << endl;
memset(&buffer, 0, 256);
read(sockfd, buffer, 256);
cout << "[Client] Server message: " << buffer << endl << endl;
cout << "============================" << endl << endl;
cout.flush();
}
}
在我再创建一个与服务器的连接之后,它可以正常工作,然后第二个客户端可以发送和接收数据,但此时第一个客户端无法正常工作。
我像这样编译我的程序:g++ server.cpp -lpthread -o server -std=c++11 然后在其他控制台选项卡中运行我编译的 client.cpp:./client。
为了检查多线程工作,我再次运行客户端(再次在另一个选项卡中)并尝试同时在两个选项卡中发送请求。
我想在我的程序中实现多线程。我该怎么做?
UPD:我正在使用 Linux
UPD2:问题已解决。修复了那里的代码。
【问题讨论】:
-
new_socket是for循环的局部变量,因此线程持有的指针在线程使用它时将指向垃圾区,这真是太奇怪了。快速修复:按值传递,而不是作为指针传递。还要查看select、epoll或重叠 IO,具体取决于您的目标操作系统。 -
如果
message_size = recv(*socket, client_message, 256, 0)读取 256 个字节,可能不相关的client_message[message_size] = '\0';将刺穿char client_message[256];并具有未定义的行为。试试message_size = recv(*socket, client_message, sizeof(client_message)-1, 0)吧。 -
@user4581301 哦,天哪.. 你的第一个提示对我有帮助,现在它工作得很好。非常感谢你:)
-
这里是一个使用 select 来处理只有一个线程的多个连接的示例:gnu.org/software/libc/manual/html_node/Server-Example.html
标签: c++ multithreading sockets c++11