我正在尝试使用p线程编写一个简单的多线程信使程序。我正在将sockfd添加到线程安全的链表中,并尝试将消息从每个客户端的处理程序线程发送到所有其他客户端。我预计过时的连接将从列表中删除,它可以正常工作,因为我采用了“C++并发操作”中的代码。使用lldb运行代码后,我发现在断开客户端连接后,服务器从信号13(即SIGPIPE)崩溃。我不知道这会在哪里发生,因为我希望WRITE返回-1,有人能帮忙吗?
Server.cpp
void *conn_handler(void *);
void send_msg(std::pair<uint32_t, char *> reply_pair);
multithread_list<int> adress_list;
int main(int argc, char *argv[]) {
(void)argc;
(void)argv;
int sockfd;
uint16_t portno;
unsigned int clilen;
struct sockaddr_in serv_addr, cli_addr;
/* First call to socket() function */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("ERROR opening socket");
exit(1);
}
/* Initialize socket structure */
bzero((char *)&serv_addr, sizeof(serv_addr));
portno = 5001;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
/* Now bind the host address using bind() call.*/
if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR on binding");
exit(1);
}
/* Now start listening for the clients, here process will
* go in sleep mode and will wait for the incoming connection
*/
while (true) {
listen(sockfd, 5);
clilen = sizeof(cli_addr);
/* Accept actual connection from the client */
int newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
adress_list.push_front(newsockfd);
pthread_t thread;
if (pthread_create(&thread, nullptr, conn_handler, (void *)&newsockfd) < 0) {
perror("ERROR creating thread.");
}
pthread_detach(thread);
}
return 0;
}
void *conn_handler(void *newsockfd_v) {
int newsockfd = *reinterpret_cast<int *>(newsockfd_v);
char buffer[256];
if (newsockfd < 0) {
perror("ERROR on accept");
exit(1);
}
while (true) {
/* If connection is established then start communicating */
bzero(buffer, 256);
ssize_t n = read(newsockfd, buffer, 255);
if (n < 0) {
printf("break");
break ;
}
data *user_data = buffer_to_data(buffer);
printf("Here is the message: %sn", user_data->body);
printf("current newsockfd = %dn", newsockfd);
/* Write a response to the client */
send_msg(data_to_buffer(user_data));
}
return nullptr;
}
void send_msg(std::pair<uint32_t, char *> reply_pair) {
adress_list.remove_if([reply_pair](int sock) {
ssize_t n = write(sock, reply_pair.second, reply_pair.first);
if (n < 0) {
return true;
}
return false;
});
}
Client.cpp
# define BUFF_SIZE 256
void remove_enter_symbol(char *buffer, size_t buff_size) {
if (buffer == nullptr) exit(1);
for (size_t i = 0; i < buff_size; i++) {
if (buffer[i] == 'n') {
buffer[i] = '0';
break;
}
}
}
size_t get_word_size(const char *buffer, size_t buff_size) {
if (buffer == nullptr) exit(1);
size_t counter = 0;
for (size_t i = 0; i < buff_size; ++i) {
if (buffer[i] != '0')
counter++;
else
break;
}
return counter;
}
void *listen_server(void *sock) {
int sockfd = *reinterpret_cast<int *>(sock);
char *receive_buffer = new char[256];
while (true) {
bzero(receive_buffer, BUFF_SIZE);
ssize_t n = read(sockfd, receive_buffer, BUFF_SIZE - 1);
if (n < 0) {
perror("ERROR reading from socket");
break;
}
server_data *d = buffer_to_struct(receive_buffer);
printf("[%s] ", d->date);
printf("%s: ", d->name);
printf("%sn", d->body);
}
return nullptr;
}
int main(int argc, char *argv[]) {
(void)argc;
(void)argv;
ssize_t sockfd, n;
uint16_t portno;
struct sockaddr_in serv_addr;
struct hostent *server;
char name_buffer[BUFF_SIZE];
char body_buffer[BUFF_SIZE];
data user_data;
if (argc < 3) {
fprintf(stderr, "usage %s hostname portn", argv[0]);
exit(0);
}
portno = (uint16_t)atoi(argv[2]);
/* Create a socket point */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("ERROR opening socket");
exit(1);
}
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr, "ERROR, no such hostn");
exit(0);
}
bzero((char *)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy(server->h_addr, (char *)&serv_addr.sin_addr.s_addr,
(size_t)server->h_length);
serv_addr.sin_port = htons(portno);
/* Now connect to the server */
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR connecting");
exit(1);
}
/* Now ask for a message from the user, this message
* will be read by server
*/
pthread_t thread;
if (pthread_create(&thread, nullptr, listen_server, (void *)&sockfd) < 0) {
perror("ERROR creating thread.");
}
pthread_detach(thread);
printf("Please enter the name: ");
bzero(name_buffer, BUFF_SIZE);
if (fgets(name_buffer, BUFF_SIZE - 1, stdin) == NULL) {
perror("ERROR reading from stdin");
pthread_kill(thread, -1);
exit(1);
}
remove_enter_symbol(name_buffer, BUFF_SIZE);
user_data.name = name_buffer;
user_data.name_size = get_word_size(name_buffer, BUFF_SIZE);
while (true) {
printf("Please enter the message: ");
bzero(body_buffer, BUFF_SIZE);
if (fgets(body_buffer, BUFF_SIZE - 1, stdin) == NULL) {
perror("ERROR reading from stdin");
pthread_kill(thread, -1);
exit(1);
}
remove_enter_symbol(body_buffer, BUFF_SIZE);
user_data.body = body_buffer;
user_data.body_size = get_word_size(body_buffer, BUFF_SIZE);
char *buff_to_send = struct_to_buffer(&user_data);
/* Send message to the server */
n = write(sockfd, buff_to_send, BUFF_SIZE);
if (n < 0) {
perror("ERROR writing to socket");
pthread_kill(thread, -1);
exit(1);
}
}
return 0;
}
1条答案
按热度按时间63lcw9qa1#
在断开客户端连接后,服务器从信号13(即SIGPIPE)崩溃
当您尝试写入打开但不再连接到任何内容的文件描述符时,会引发
SIGPIPE
。当读取端关闭时,使用管道可以很容易地实现这一点。这就是它的助记符。在类似的情况下,插座也可能发生这种情况。我不知道这会在哪里发生,因为我希望WRITE返回-1
write()
可能确实返回-1,或者如果您处理SIGPIPE
,会返回-1。这是write()
的Linux手册页面的相关部分: