客户端在新建立的连接上收不到消息
Client does not receive message on newly formed connection
所以我有一个非常简单的多服务器-客户端应用程序 (Linux)。我想为初学者做的是连接到服务器接收来自它的消息并将消息写入服务器然后回声。
问题是在连接上而不是来自服务器的问候消息,客户端准备将消息键入终端 - 没有问候消息。输入我想要的任何消息后,我会收到问候消息!我在这里做错了什么?下面的代码。
server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <pthread.h>
#include <netdb.h>
#include <netinet/in.h>
int server(int client_socket);
void* handle_connection(void* inc);
int main(int argc, char* argv[])
{
int socket_fd;
int client_socket_fd;
int port_number;
int client_length;
int * new_sock;
struct sockaddr_in serv_addr;
struct sockaddr_in cli_addr;
char buffer[256];
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if(socket_fd < 0) {
perror("Error opening socket!");
exit(1);
}
/* Initialize socket structure */
port_number = 1234;
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr= INADDR_ANY;
serv_addr.sin_port = htons(port_number);
/* Binding */
if(bind(socket_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("Error on binding!");
exit(1);
}
listen(socket_fd, 10);
client_length = sizeof(cli_addr);
while(client_socket_fd = accept(socket_fd, (struct sockaddr*) &cli_addr, &client_length)) {
pthread_t thread_id;
new_sock = malloc(sizeof(client_socket_fd));
*new_sock = client_socket_fd;
if(pthread_create(&thread_id, NULL, handle_connection, (void*) new_sock)) {
perror("could not create thread");
exit(1);
}
pthread_join(thread_id, NULL);
}
if(client_socket_fd < 0) {
perror("Error on accept client");
exit(1);
}
return 0;
}
void* handle_connection(void* inc)
{
int socket_fd = *(int *) inc;
int message_size;
char *message;
char buffer[256];
message = "You have been connected\n";
write(socket_fd, message, strlen(message));
message = "I will repeat what you type\n";
write(socket_fd, message, strlen(message));
while((message_size = recv(socket_fd, buffer, sizeof(buffer)/sizeof(buffer[0]), 0)) > 0) {
write(socket_fd, buffer, strlen(buffer));
}
if(message_size == 0) {
puts("Client disconnected");
fflush(stdout);
}
else if(message_size == -1) {
perror("Reading back from client failed");
}
free(inc);
return 0;
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <pthread.h>
int main(int argc, char* argv[])
{
int socket_fd, port_number;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if(argc<2) {
fprintf(stderr,"Incorrect arguments input\n");
exit(0);
}
//port_number = atoi(argv[2]);
port_number = 1234;
server = gethostbyname(argv[1]);
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if(socket_fd < 0) {
perror("Error opening socket");
exit(1);
}
bzero((char*) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port_number);
bcopy((char*) server->h_addr,(char *) &serv_addr.sin_addr.s_addr,sizeof(server->h_length));
if(connect(socket_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("Error connecting");
exit(1);
}
while(1) {
bzero(buffer, sizeof(buffer)/sizeof(buffer[0]));
printf("Enter the message: ");
bzero(buffer, sizeof(buffer)/sizeof(buffer[0]));
fgets(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, stdin);
if(send(socket_fd, buffer, strlen(buffer), 0) < 0) {
perror("Error sending message");
exit(1);
}
bzero(buffer, sizeof(buffer)/sizeof(buffer[0]));
if(recv(socket_fd, buffer, sizeof(buffer), 0) < 0) {
perror("Error reading back from server");
exit(1);
}
printf("Server reply: ");
printf("%s",buffer);
}
close(socket_fd);
return 0;
}
这是程序的意外结果:
示例中的服务器回复应该是:hej.
The problem is that on connection instead of greetings message from server, client is ready to type the message ito the terminal - there is no greetings message.
这是因为在使用 recv()
获取问候语并将其显示给用户之前,您正在读取用户输入。
After typing whatever message I want I get echoed back with the greetings message!
这是因为您是fetching/showing在来电后的问候
fgets()
.
代码中存在一些错误。我会指出最大的。
- 您在
pthread_create()
之后立即呼叫 pthread_join()
。那是
阻止新连接(即 accept()
s)。应该这样做
在循环之外。在这种情况下,您需要一些线程 ID 存储空间。为了
示例:
const int thread_pool_step = 10;
int thread_pool_size = thread_pool_step;
pthread_t *thread_ids = malloc(thread_pool_size * sizeof(pthread_t));
memset(thread_ids, 0, thread_pool_size * sizeof(pthread_t));
int thread_index = -1;
while (!do_shutdown)
{
/* ... */
if (++thread_index >= thread_pool_size)
{
thread_pool_size += thread_pool_step;
thread_ids = realloc(thread_ids, thread_pool_size * sizeof(pthread_t));
if (thread_ids == NULL)
{
fprintf(stderr, "failed to realloc thread pool: %s\n",
strerror(errno));
abort();
}
}
pthread_create(&thread_ids[thread_index++], NULL,
handle_connection, (void*) new_sock);
}
while (--thread_index >= 0)
{
if (thread_ids[thread_index])
pthread_join(thread_ids[thread_index], NULL);
}
if (thread_ids != NULL)
free(thread_ids);
- 如问题评论中所述,您需要某种
协议。例如,您可能会阅读问候语,直到服务器发送
从 "READY" 字符串开始的行。客户端可能会记住服务器状态,然后继续聊天逻辑:
enum {
INIT_STATE,
READY_STATE
} serv_state = INIT_STATE;
#define check_serv_state(str, st) \
(strncmp(str, #st, sizeof(#st) - 1) == 0)
for (;;)
{
bzero(buffer, sizeof(buffer)/sizeof(buffer[0]));
rc = recv(socket_fd, buffer, sizeof(buffer), 0);
/* ... */
if (serv_state == INIT_STATE)
{
char *part = strtok(buffer, "\n");
do
{
if (check_serv_state(part, READY))
{
printf("The server is ready for the chat\n");
serv_state = READY_STATE;
}
else
printf("Server: [[[%s]]]\n", part);
}
while ((part = strtok(NULL, "\n")));
if (serv_state != READY_STATE)
continue;
}
else
printf("Server reply: %s", buffer);
/* ... */
printf("Enter the message: ");
/* ... */
}
- 我还建议为正常关机实施一些信号处理。至少,对于服务器:
volatile sig_atomic_t do_shutdown = 0; /* global */
static void
sigterm_handler(int sig)
{
printf("Caught signal %d. Leaving...\n", sig);
do_shutdown = 1;
}
/* ... */
struct sigaction a;
a.sa_handler = sigterm_handler;
a.sa_flags = 0;
sigemptyset(&a.sa_mask);
sigaction(SIGINT, &a, NULL);
sigaction(SIGQUIT, &a, NULL);
sigaction(SIGTERM, &a, NULL);
/* Check do_shutdown in the loops */
while (!do_shutdown) { /* ...recv(), accept(), etc. */ }
请注意,如果不使用 mutual exclusion,从异步上下文(信号处理程序、线程处理程序[尤其是])访问全局变量通常是不安全的。
下面是应用了修复的完整代码:
server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <signal.h>
#include <netdb.h>
#include <netinet/in.h>
volatile sig_atomic_t do_shutdown = 0;
static void
sigterm_handler(int sig)
{
printf("Caught signal %d. Leaving...\n", sig);
do_shutdown = 1;
}
static void
send_message(int socket_fd, const char *message)
{
int rc;
int message_size = strlen(message);
do
{
rc = send(socket_fd, message, message_size, 0);
if (rc == -1)
{
fprintf(stderr, "send() failed: %s\n", strerror(errno));
abort();
}
}
while (rc < message_size && !do_shutdown);
}
static void *
handle_connection(void *inc)
{
int socket_fd = *(int *)inc;
int message_size;
char *message;
char buffer[256];
message = "You have been connected\n";
send_message(socket_fd, message);
message = "I will repeat what you type\n";
send_message(socket_fd, message);
message = "READY\n";
send_message(socket_fd, message);
while (!do_shutdown)
{
memset(buffer, 0, sizeof(buffer));
message_size = recv(socket_fd, buffer, sizeof(buffer) / sizeof(buffer[0]), 0);
if (message_size > 0)
send_message(socket_fd, buffer);
else if (message_size == -1)
{
fprintf(stderr, "recv() failed: %s\n", strerror(errno));
break;
}
else if (message_size == 0)
{
puts("Client disconnected");
fflush(stdout);
break;
}
}
free(inc);
return 0;
}
int
main(int argc, char* argv[])
{
int socket_fd;
int client_socket_fd;
int port_number;
socklen_t client_length;
int *new_sock;
struct sockaddr_in serv_addr;
struct sockaddr_in cli_addr;
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd < 0)
{
perror("Error opening socket!");
exit(1);
}
/* Initialize socket structure */
port_number = 12345;
bzero((char *)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr= INADDR_ANY;
serv_addr.sin_port = htons(port_number);
/* Binding */
if (bind(socket_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
{
perror("Error on binding!");
exit(1);
}
const int thread_pool_step = 10;
listen(socket_fd, thread_pool_step);
client_length = sizeof(cli_addr);
int thread_pool_size = thread_pool_step;
pthread_t *thread_ids = malloc(thread_pool_size * sizeof(pthread_t));
if (thread_ids == NULL)
{
perror("Failed to allocate memory for thread ids");
abort();
}
memset(thread_ids, 0, thread_pool_size * sizeof(pthread_t));
int thread_index = -1;
struct sigaction a;
a.sa_handler = sigterm_handler;
a.sa_flags = 0;
sigemptyset(&a.sa_mask);
sigaction(SIGINT, &a, NULL);
sigaction(SIGQUIT, &a, NULL);
sigaction(SIGTERM, &a, NULL);
while (!do_shutdown)
{
client_socket_fd = accept(socket_fd, (struct sockaddr *)(&cli_addr), &client_length);
if (client_socket_fd == -1)
{
fprintf(stderr, "accept() failed: %s\n", strerror(errno));
break;
}
new_sock = malloc(sizeof(client_socket_fd));
*new_sock = client_socket_fd;
if (++thread_index >= thread_pool_size)
{
thread_pool_size += thread_pool_step;
thread_ids = realloc(thread_ids, thread_pool_size * sizeof(pthread_t));
if (thread_ids == NULL)
{
fprintf(stderr, "failed to realloc thread pool: %s\n", strerror(errno));
abort();
}
}
if (pthread_create(&thread_ids[thread_index++], NULL,
handle_connection, (void*) new_sock))
{
fprintf(stderr, "pthread_create() failed: %s\n", strerror(errno));
abort();
}
}
puts("Waiting for threads to finish");
while (--thread_index >= 0)
{
if (thread_ids[thread_index])
pthread_join(thread_ids[thread_index], NULL);
}
if (thread_ids != NULL)
free(thread_ids);
return 0;
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
int socket_fd, port_number;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
int rc;
if (argc<2)
{
fprintf(stderr,"Incorrect arguments input\n");
exit(0);
}
port_number = 12345;
server = gethostbyname(argv[1]);
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd < 0)
{
perror("Error opening socket");
exit(1);
}
bzero((char*) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port_number);
bcopy((char*) server->h_addr,(char *)
&serv_addr.sin_addr.s_addr,sizeof(server->h_length));
if (connect(socket_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
perror("Error connecting");
exit(1);
}
enum
{
INIT_STATE,
READY_STATE
} serv_state = INIT_STATE;
#define check_serv_state(str, st) \
(strncmp(str, #st, sizeof(#st) - 1) == 0)
for (;;)
{
bzero(buffer, sizeof(buffer)/sizeof(buffer[0]));
rc = recv(socket_fd, buffer, sizeof(buffer), 0);
if (rc < 0)
{
perror("Error reading back from server");
exit(1);
}
else if (rc == 0)
{
printf("The server has been disconnected. Quitting.\n");
exit(0);
}
if (serv_state == INIT_STATE)
{
char *part = strtok(buffer, "\n");
do
{
if (check_serv_state(part, READY))
{
printf("The server is ready for the chat\n");
serv_state = READY_STATE;
}
else
printf("Server: [[[%s]]]\n", part);
}
while ((part = strtok(NULL, "\n")));
if (serv_state != READY_STATE)
continue;
}
else
printf("Server reply: %s", buffer);
bzero(buffer, sizeof(buffer)/sizeof(buffer[0]));
printf("Enter the message: ");
bzero(buffer, sizeof(buffer)/sizeof(buffer[0]));
fgets(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, stdin);
if (send(socket_fd, buffer, strlen(buffer), 0) < 0)
{
perror("Error sending message");
exit(1);
}
}
close(socket_fd);
return 0;
}
所以我有一个非常简单的多服务器-客户端应用程序 (Linux)。我想为初学者做的是连接到服务器接收来自它的消息并将消息写入服务器然后回声。
问题是在连接上而不是来自服务器的问候消息,客户端准备将消息键入终端 - 没有问候消息。输入我想要的任何消息后,我会收到问候消息!我在这里做错了什么?下面的代码。
server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <pthread.h>
#include <netdb.h>
#include <netinet/in.h>
int server(int client_socket);
void* handle_connection(void* inc);
int main(int argc, char* argv[])
{
int socket_fd;
int client_socket_fd;
int port_number;
int client_length;
int * new_sock;
struct sockaddr_in serv_addr;
struct sockaddr_in cli_addr;
char buffer[256];
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if(socket_fd < 0) {
perror("Error opening socket!");
exit(1);
}
/* Initialize socket structure */
port_number = 1234;
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr= INADDR_ANY;
serv_addr.sin_port = htons(port_number);
/* Binding */
if(bind(socket_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("Error on binding!");
exit(1);
}
listen(socket_fd, 10);
client_length = sizeof(cli_addr);
while(client_socket_fd = accept(socket_fd, (struct sockaddr*) &cli_addr, &client_length)) {
pthread_t thread_id;
new_sock = malloc(sizeof(client_socket_fd));
*new_sock = client_socket_fd;
if(pthread_create(&thread_id, NULL, handle_connection, (void*) new_sock)) {
perror("could not create thread");
exit(1);
}
pthread_join(thread_id, NULL);
}
if(client_socket_fd < 0) {
perror("Error on accept client");
exit(1);
}
return 0;
}
void* handle_connection(void* inc)
{
int socket_fd = *(int *) inc;
int message_size;
char *message;
char buffer[256];
message = "You have been connected\n";
write(socket_fd, message, strlen(message));
message = "I will repeat what you type\n";
write(socket_fd, message, strlen(message));
while((message_size = recv(socket_fd, buffer, sizeof(buffer)/sizeof(buffer[0]), 0)) > 0) {
write(socket_fd, buffer, strlen(buffer));
}
if(message_size == 0) {
puts("Client disconnected");
fflush(stdout);
}
else if(message_size == -1) {
perror("Reading back from client failed");
}
free(inc);
return 0;
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <pthread.h>
int main(int argc, char* argv[])
{
int socket_fd, port_number;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if(argc<2) {
fprintf(stderr,"Incorrect arguments input\n");
exit(0);
}
//port_number = atoi(argv[2]);
port_number = 1234;
server = gethostbyname(argv[1]);
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if(socket_fd < 0) {
perror("Error opening socket");
exit(1);
}
bzero((char*) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port_number);
bcopy((char*) server->h_addr,(char *) &serv_addr.sin_addr.s_addr,sizeof(server->h_length));
if(connect(socket_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("Error connecting");
exit(1);
}
while(1) {
bzero(buffer, sizeof(buffer)/sizeof(buffer[0]));
printf("Enter the message: ");
bzero(buffer, sizeof(buffer)/sizeof(buffer[0]));
fgets(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, stdin);
if(send(socket_fd, buffer, strlen(buffer), 0) < 0) {
perror("Error sending message");
exit(1);
}
bzero(buffer, sizeof(buffer)/sizeof(buffer[0]));
if(recv(socket_fd, buffer, sizeof(buffer), 0) < 0) {
perror("Error reading back from server");
exit(1);
}
printf("Server reply: ");
printf("%s",buffer);
}
close(socket_fd);
return 0;
}
这是程序的意外结果:
示例中的服务器回复应该是:hej.
The problem is that on connection instead of greetings message from server, client is ready to type the message ito the terminal - there is no greetings message.
这是因为在使用 recv()
获取问候语并将其显示给用户之前,您正在读取用户输入。
After typing whatever message I want I get echoed back with the greetings message!
这是因为您是fetching/showing在来电后的问候
fgets()
.
代码中存在一些错误。我会指出最大的。
- 您在
pthread_create()
之后立即呼叫pthread_join()
。那是 阻止新连接(即accept()
s)。应该这样做 在循环之外。在这种情况下,您需要一些线程 ID 存储空间。为了 示例:
const int thread_pool_step = 10;
int thread_pool_size = thread_pool_step;
pthread_t *thread_ids = malloc(thread_pool_size * sizeof(pthread_t));
memset(thread_ids, 0, thread_pool_size * sizeof(pthread_t));
int thread_index = -1;
while (!do_shutdown)
{
/* ... */
if (++thread_index >= thread_pool_size)
{
thread_pool_size += thread_pool_step;
thread_ids = realloc(thread_ids, thread_pool_size * sizeof(pthread_t));
if (thread_ids == NULL)
{
fprintf(stderr, "failed to realloc thread pool: %s\n",
strerror(errno));
abort();
}
}
pthread_create(&thread_ids[thread_index++], NULL,
handle_connection, (void*) new_sock);
}
while (--thread_index >= 0)
{
if (thread_ids[thread_index])
pthread_join(thread_ids[thread_index], NULL);
}
if (thread_ids != NULL)
free(thread_ids);
- 如问题评论中所述,您需要某种 协议。例如,您可能会阅读问候语,直到服务器发送 从 "READY" 字符串开始的行。客户端可能会记住服务器状态,然后继续聊天逻辑:
enum {
INIT_STATE,
READY_STATE
} serv_state = INIT_STATE;
#define check_serv_state(str, st) \
(strncmp(str, #st, sizeof(#st) - 1) == 0)
for (;;)
{
bzero(buffer, sizeof(buffer)/sizeof(buffer[0]));
rc = recv(socket_fd, buffer, sizeof(buffer), 0);
/* ... */
if (serv_state == INIT_STATE)
{
char *part = strtok(buffer, "\n");
do
{
if (check_serv_state(part, READY))
{
printf("The server is ready for the chat\n");
serv_state = READY_STATE;
}
else
printf("Server: [[[%s]]]\n", part);
}
while ((part = strtok(NULL, "\n")));
if (serv_state != READY_STATE)
continue;
}
else
printf("Server reply: %s", buffer);
/* ... */
printf("Enter the message: ");
/* ... */
}
- 我还建议为正常关机实施一些信号处理。至少,对于服务器:
volatile sig_atomic_t do_shutdown = 0; /* global */
static void
sigterm_handler(int sig)
{
printf("Caught signal %d. Leaving...\n", sig);
do_shutdown = 1;
}
/* ... */
struct sigaction a;
a.sa_handler = sigterm_handler;
a.sa_flags = 0;
sigemptyset(&a.sa_mask);
sigaction(SIGINT, &a, NULL);
sigaction(SIGQUIT, &a, NULL);
sigaction(SIGTERM, &a, NULL);
/* Check do_shutdown in the loops */
while (!do_shutdown) { /* ...recv(), accept(), etc. */ }
请注意,如果不使用 mutual exclusion,从异步上下文(信号处理程序、线程处理程序[尤其是])访问全局变量通常是不安全的。
下面是应用了修复的完整代码:
server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <signal.h>
#include <netdb.h>
#include <netinet/in.h>
volatile sig_atomic_t do_shutdown = 0;
static void
sigterm_handler(int sig)
{
printf("Caught signal %d. Leaving...\n", sig);
do_shutdown = 1;
}
static void
send_message(int socket_fd, const char *message)
{
int rc;
int message_size = strlen(message);
do
{
rc = send(socket_fd, message, message_size, 0);
if (rc == -1)
{
fprintf(stderr, "send() failed: %s\n", strerror(errno));
abort();
}
}
while (rc < message_size && !do_shutdown);
}
static void *
handle_connection(void *inc)
{
int socket_fd = *(int *)inc;
int message_size;
char *message;
char buffer[256];
message = "You have been connected\n";
send_message(socket_fd, message);
message = "I will repeat what you type\n";
send_message(socket_fd, message);
message = "READY\n";
send_message(socket_fd, message);
while (!do_shutdown)
{
memset(buffer, 0, sizeof(buffer));
message_size = recv(socket_fd, buffer, sizeof(buffer) / sizeof(buffer[0]), 0);
if (message_size > 0)
send_message(socket_fd, buffer);
else if (message_size == -1)
{
fprintf(stderr, "recv() failed: %s\n", strerror(errno));
break;
}
else if (message_size == 0)
{
puts("Client disconnected");
fflush(stdout);
break;
}
}
free(inc);
return 0;
}
int
main(int argc, char* argv[])
{
int socket_fd;
int client_socket_fd;
int port_number;
socklen_t client_length;
int *new_sock;
struct sockaddr_in serv_addr;
struct sockaddr_in cli_addr;
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd < 0)
{
perror("Error opening socket!");
exit(1);
}
/* Initialize socket structure */
port_number = 12345;
bzero((char *)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr= INADDR_ANY;
serv_addr.sin_port = htons(port_number);
/* Binding */
if (bind(socket_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
{
perror("Error on binding!");
exit(1);
}
const int thread_pool_step = 10;
listen(socket_fd, thread_pool_step);
client_length = sizeof(cli_addr);
int thread_pool_size = thread_pool_step;
pthread_t *thread_ids = malloc(thread_pool_size * sizeof(pthread_t));
if (thread_ids == NULL)
{
perror("Failed to allocate memory for thread ids");
abort();
}
memset(thread_ids, 0, thread_pool_size * sizeof(pthread_t));
int thread_index = -1;
struct sigaction a;
a.sa_handler = sigterm_handler;
a.sa_flags = 0;
sigemptyset(&a.sa_mask);
sigaction(SIGINT, &a, NULL);
sigaction(SIGQUIT, &a, NULL);
sigaction(SIGTERM, &a, NULL);
while (!do_shutdown)
{
client_socket_fd = accept(socket_fd, (struct sockaddr *)(&cli_addr), &client_length);
if (client_socket_fd == -1)
{
fprintf(stderr, "accept() failed: %s\n", strerror(errno));
break;
}
new_sock = malloc(sizeof(client_socket_fd));
*new_sock = client_socket_fd;
if (++thread_index >= thread_pool_size)
{
thread_pool_size += thread_pool_step;
thread_ids = realloc(thread_ids, thread_pool_size * sizeof(pthread_t));
if (thread_ids == NULL)
{
fprintf(stderr, "failed to realloc thread pool: %s\n", strerror(errno));
abort();
}
}
if (pthread_create(&thread_ids[thread_index++], NULL,
handle_connection, (void*) new_sock))
{
fprintf(stderr, "pthread_create() failed: %s\n", strerror(errno));
abort();
}
}
puts("Waiting for threads to finish");
while (--thread_index >= 0)
{
if (thread_ids[thread_index])
pthread_join(thread_ids[thread_index], NULL);
}
if (thread_ids != NULL)
free(thread_ids);
return 0;
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
int socket_fd, port_number;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
int rc;
if (argc<2)
{
fprintf(stderr,"Incorrect arguments input\n");
exit(0);
}
port_number = 12345;
server = gethostbyname(argv[1]);
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd < 0)
{
perror("Error opening socket");
exit(1);
}
bzero((char*) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port_number);
bcopy((char*) server->h_addr,(char *)
&serv_addr.sin_addr.s_addr,sizeof(server->h_length));
if (connect(socket_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
perror("Error connecting");
exit(1);
}
enum
{
INIT_STATE,
READY_STATE
} serv_state = INIT_STATE;
#define check_serv_state(str, st) \
(strncmp(str, #st, sizeof(#st) - 1) == 0)
for (;;)
{
bzero(buffer, sizeof(buffer)/sizeof(buffer[0]));
rc = recv(socket_fd, buffer, sizeof(buffer), 0);
if (rc < 0)
{
perror("Error reading back from server");
exit(1);
}
else if (rc == 0)
{
printf("The server has been disconnected. Quitting.\n");
exit(0);
}
if (serv_state == INIT_STATE)
{
char *part = strtok(buffer, "\n");
do
{
if (check_serv_state(part, READY))
{
printf("The server is ready for the chat\n");
serv_state = READY_STATE;
}
else
printf("Server: [[[%s]]]\n", part);
}
while ((part = strtok(NULL, "\n")));
if (serv_state != READY_STATE)
continue;
}
else
printf("Server reply: %s", buffer);
bzero(buffer, sizeof(buffer)/sizeof(buffer[0]));
printf("Enter the message: ");
bzero(buffer, sizeof(buffer)/sizeof(buffer[0]));
fgets(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, stdin);
if (send(socket_fd, buffer, strlen(buffer), 0) < 0)
{
perror("Error sending message");
exit(1);
}
}
close(socket_fd);
return 0;
}