-
-
Save Alexey-N-Chernyshov/4634731 to your computer and use it in GitHub Desktop.
| // Simple example of client. | |
| // Client prints received messages to stdout and sends from stdin. | |
| #include <errno.h> | |
| #include <fcntl.h> | |
| #include <stdio.h> | |
| #include <signal.h> | |
| #include <unistd.h> | |
| #include <sys/select.h> | |
| #include <netinet/in.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include "message.h" | |
| peer_t server; | |
| void shutdown_properly(int code); | |
| void handle_signal_action(int sig_number) | |
| { | |
| if (sig_number == SIGINT) { | |
| printf("SIGINT was catched!\n"); | |
| shutdown_properly(EXIT_SUCCESS); | |
| } | |
| else if (sig_number == SIGPIPE) { | |
| printf("SIGPIPE was catched!\n"); | |
| shutdown_properly(EXIT_SUCCESS); | |
| } | |
| } | |
| int setup_signals() | |
| { | |
| struct sigaction sa; | |
| sa.sa_handler = handle_signal_action; | |
| if (sigaction(SIGINT, &sa, 0) != 0) { | |
| perror("sigaction()"); | |
| return -1; | |
| } | |
| if (sigaction(SIGPIPE, &sa, 0) != 0) { | |
| perror("sigaction()"); | |
| return -1; | |
| } | |
| return 0; | |
| } | |
| int get_client_name(int argc, char **argv, char *client_name) | |
| { | |
| if (argc > 1) | |
| strcpy(client_name, argv[1]); | |
| else | |
| strcpy(client_name, "no name"); | |
| return 0; | |
| } | |
| int connect_server(peer_t *server) | |
| { | |
| // create socket | |
| server->socket = socket(AF_INET, SOCK_STREAM, 0); | |
| if (server->socket < 0) { | |
| perror("socket()"); | |
| return -1; | |
| } | |
| // set up addres | |
| struct sockaddr_in server_addr; | |
| memset(&server_addr, 0, sizeof(server_addr)); | |
| server_addr.sin_family = AF_INET; | |
| server_addr.sin_addr.s_addr = inet_addr(SERVER_IPV4_ADDR); | |
| server_addr.sin_port = htons(SERVER_LISTEN_PORT); | |
| server->addres = server_addr; | |
| if (connect(server->socket, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) != 0) { | |
| perror("connect()"); | |
| return -1; | |
| } | |
| printf("Connected to %s:%d.\n", SERVER_IPV4_ADDR, SERVER_LISTEN_PORT); | |
| return 0; | |
| } | |
| int build_fd_sets(peer_t *server, fd_set *read_fds, fd_set *write_fds, fd_set *except_fds) | |
| { | |
| FD_ZERO(read_fds); | |
| FD_SET(STDIN_FILENO, read_fds); | |
| FD_SET(server->socket, read_fds); | |
| FD_ZERO(write_fds); | |
| // there is smth to send, set up write_fd for server socket | |
| if (server->send_buffer.current > 0) | |
| FD_SET(server->socket, write_fds); | |
| FD_ZERO(except_fds); | |
| FD_SET(STDIN_FILENO, except_fds); | |
| FD_SET(server->socket, except_fds); | |
| return 0; | |
| } | |
| int handle_read_from_stdin(peer_t *server, char *client_name) | |
| { | |
| char read_buffer[DATA_MAXSIZE]; // buffer for stdin | |
| if (read_from_stdin(read_buffer, DATA_MAXSIZE) != 0) | |
| return -1; | |
| // Create new message and enqueue it. | |
| message_t new_message; | |
| prepare_message(client_name, read_buffer, &new_message); | |
| print_message(&new_message); | |
| if (peer_add_to_send(server, &new_message) != 0) { | |
| printf("Send buffer is overflowed, we lost this message!\n"); | |
| return 0; | |
| } | |
| printf("New message to send was enqueued right now.\n"); | |
| return 0; | |
| } | |
| /* You should be careful when using this function in multythread program. | |
| * Ensure that server is thread-safe. */ | |
| void shutdown_properly(int code) | |
| { | |
| delete_peer(&server); | |
| printf("Shutdown client properly.\n"); | |
| exit(code); | |
| } | |
| int handle_received_message(message_t *message) | |
| { | |
| printf("Received message from server.\n"); | |
| print_message(message); | |
| return 0; | |
| } | |
| int main(int argc, char **argv) | |
| { | |
| if (setup_signals() != 0) | |
| exit(EXIT_FAILURE); | |
| char client_name[256]; | |
| get_client_name(argc, argv, client_name); | |
| printf("Client '%s' start.\n", client_name); | |
| create_peer(&server); | |
| if (connect_server(&server) != 0) | |
| shutdown_properly(EXIT_FAILURE); | |
| /* Set nonblock for stdin. */ | |
| int flag = fcntl(STDIN_FILENO, F_GETFL, 0); | |
| flag |= O_NONBLOCK; | |
| fcntl(STDIN_FILENO, F_SETFL, flag); | |
| fd_set read_fds; | |
| fd_set write_fds; | |
| fd_set except_fds; | |
| printf("Waiting for server message or stdin input. Please, type text to send:\n"); | |
| // server socket always will be greater then STDIN_FILENO | |
| int maxfd = server.socket; | |
| while (1) { | |
| // Select() updates fd_set's, so we need to build fd_set's before each select()call. | |
| build_fd_sets(&server, &read_fds, &write_fds, &except_fds); | |
| int activity = select(maxfd + 1, &read_fds, &write_fds, &except_fds, NULL); | |
| switch (activity) { | |
| case -1: | |
| perror("select()"); | |
| shutdown_properly(EXIT_FAILURE); | |
| case 0: | |
| // you should never get here | |
| printf("select() returns 0.\n"); | |
| shutdown_properly(EXIT_FAILURE); | |
| default: | |
| /* All fd_set's should be checked. */ | |
| if (FD_ISSET(STDIN_FILENO, &read_fds)) { | |
| if (handle_read_from_stdin(&server, client_name) != 0) | |
| shutdown_properly(EXIT_FAILURE); | |
| } | |
| if (FD_ISSET(STDIN_FILENO, &except_fds)) { | |
| printf("except_fds for stdin.\n"); | |
| shutdown_properly(EXIT_FAILURE); | |
| } | |
| if (FD_ISSET(server.socket, &read_fds)) { | |
| if (receive_from_peer(&server, &handle_received_message) != 0) | |
| shutdown_properly(EXIT_FAILURE); | |
| } | |
| if (FD_ISSET(server.socket, &write_fds)) { | |
| if (send_to_peer(&server) != 0) | |
| shutdown_properly(EXIT_FAILURE); | |
| } | |
| if (FD_ISSET(server.socket, &except_fds)) { | |
| printf("except_fds for server.\n"); | |
| shutdown_properly(EXIT_FAILURE); | |
| } | |
| } | |
| printf("And we are still waiting for server or stdin activity. You can type something to send:\n"); | |
| } | |
| return 0; | |
| } |
| #ifndef MESSAGE_H | |
| #define MESSAGE_H | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| /* Maximum bytes that can be send() or recv() via net by one call. | |
| * It's a good idea to test sending one byte by one. | |
| */ | |
| #define MAX_SEND_SIZE 100 | |
| /* Size of send queue (messages). */ | |
| #define MAX_MESSAGES_BUFFER_SIZE 10 | |
| #define SENDER_MAXSIZE 128 | |
| #define DATA_MAXSIZE 512 | |
| #define SERVER_IPV4_ADDR "127.0.0.1" | |
| #define SERVER_LISTEN_PORT 33235 | |
| // message -------------------------------------------------------------------- | |
| typedef struct { | |
| char sender[SENDER_MAXSIZE]; | |
| char data[DATA_MAXSIZE]; | |
| } message_t; | |
| int prepare_message(char *sender, char *data, message_t *message) | |
| { | |
| sprintf(message->sender, "%s", sender); | |
| sprintf(message->data, "%s", data); | |
| return 0; | |
| } | |
| int print_message(message_t *message) | |
| { | |
| printf("Message: \"%s: %s\"\n", message->sender, message->data); | |
| return 0; | |
| } | |
| // message queue -------------------------------------------------------------- | |
| typedef struct { | |
| int size; | |
| message_t *data; | |
| int current; | |
| } message_queue_t; | |
| int create_message_queue(int queue_size, message_queue_t *queue) | |
| { | |
| queue->data = calloc(queue_size, sizeof(message_t)); | |
| queue->size = queue_size; | |
| queue->current = 0; | |
| return 0; | |
| } | |
| void delete_message_queue(message_queue_t *queue) | |
| { | |
| free(queue->data); | |
| queue->data = NULL; | |
| } | |
| int enqueue(message_queue_t *queue, message_t *message) | |
| { | |
| if (queue->current == queue->size) | |
| return -1; | |
| memcpy(&queue->data[queue->current], message, sizeof(message_t)); | |
| queue->current++; | |
| return 0; | |
| } | |
| int dequeue(message_queue_t *queue, message_t *message) | |
| { | |
| if (queue->current == 0) | |
| return -1; | |
| memcpy(message, &queue->data[queue->current - 1], sizeof(message_t)); | |
| queue->current--; | |
| return 0; | |
| } | |
| int dequeue_all(message_queue_t *queue) | |
| { | |
| queue->current = 0; | |
| return 0; | |
| } | |
| // peer ----------------------------------------------------------------------- | |
| typedef struct { | |
| int socket; | |
| struct sockaddr_in addres; | |
| /* Messages that waiting for send. */ | |
| message_queue_t send_buffer; | |
| /* Buffered sending message. | |
| * | |
| * In case we doesn't send whole message per one call send(). | |
| * And current_sending_byte is a pointer to the part of data that will be send next call. | |
| */ | |
| message_t sending_buffer; | |
| size_t current_sending_byte; | |
| /* The same for the receiving message. */ | |
| message_t receiving_buffer; | |
| size_t current_receiving_byte; | |
| } peer_t; | |
| int delete_peer(peer_t *peer) | |
| { | |
| close(peer->socket); | |
| delete_message_queue(&peer->send_buffer); | |
| } | |
| int create_peer(peer_t *peer) | |
| { | |
| create_message_queue(MAX_MESSAGES_BUFFER_SIZE, &peer->send_buffer); | |
| peer->current_sending_byte = -1; | |
| peer->current_receiving_byte = 0; | |
| return 0; | |
| } | |
| char *peer_get_addres_str(peer_t *peer) | |
| { | |
| static char ret[INET_ADDRSTRLEN + 10]; | |
| char peer_ipv4_str[INET_ADDRSTRLEN]; | |
| inet_ntop(AF_INET, &peer->addres.sin_addr, peer_ipv4_str, INET_ADDRSTRLEN); | |
| sprintf(ret, "%s:%d", peer_ipv4_str, peer->addres.sin_port); | |
| return ret; | |
| } | |
| int peer_add_to_send(peer_t *peer, message_t *message) | |
| { | |
| return enqueue(&peer->send_buffer, message); | |
| } | |
| /* Receive message from peer and handle it with message_handler(). */ | |
| int receive_from_peer(peer_t *peer, int (*message_handler)(message_t *)) | |
| { | |
| printf("Ready for recv() from %s.\n", peer_get_addres_str(peer)); | |
| size_t len_to_receive; | |
| ssize_t received_count; | |
| size_t received_total = 0; | |
| do { | |
| // Is completely received? | |
| if (peer->current_receiving_byte >= sizeof(peer->receiving_buffer)) { | |
| message_handler(&peer->receiving_buffer); | |
| peer->current_receiving_byte = 0; | |
| } | |
| // Count bytes to send. | |
| len_to_receive = sizeof(peer->receiving_buffer) - peer->current_receiving_byte; | |
| if (len_to_receive > MAX_SEND_SIZE) | |
| len_to_receive = MAX_SEND_SIZE; | |
| printf("Let's try to recv() %zd bytes... ", len_to_receive); | |
| received_count = recv(peer->socket, (char *)&peer->receiving_buffer + peer->current_receiving_byte, len_to_receive, MSG_DONTWAIT); | |
| if (received_count < 0) { | |
| if (errno == EAGAIN || errno == EWOULDBLOCK) { | |
| printf("peer is not ready right now, try again later.\n"); | |
| } | |
| else { | |
| perror("recv() from peer error"); | |
| return -1; | |
| } | |
| } | |
| else if (received_count < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { | |
| break; | |
| } | |
| // If recv() returns 0, it means that peer gracefully shutdown. Shutdown client. | |
| else if (received_count == 0) { | |
| printf("recv() 0 bytes. Peer gracefully shutdown.\n"); | |
| return -1; | |
| } | |
| else if (received_count > 0) { | |
| peer->current_receiving_byte += received_count; | |
| received_total += received_count; | |
| printf("recv() %zd bytes\n", received_count); | |
| } | |
| } while (received_count > 0); | |
| printf("Total recv()'ed %zu bytes.\n", received_total); | |
| return 0; | |
| } | |
| int send_to_peer(peer_t *peer) | |
| { | |
| printf("Ready for send() to %s.\n", peer_get_addres_str(peer)); | |
| size_t len_to_send; | |
| ssize_t send_count; | |
| size_t send_total = 0; | |
| do { | |
| // If sending message has completely sent and there are messages in queue, why not send them? | |
| if (peer->current_sending_byte < 0 || peer->current_sending_byte >= sizeof(peer->sending_buffer)) { | |
| printf("There is no pending to send() message, maybe we can find one in queue... "); | |
| if (dequeue(&peer->send_buffer, &peer->sending_buffer) != 0) { | |
| peer->current_sending_byte = -1; | |
| printf("No, there is nothing to send() anymore.\n"); | |
| break; | |
| } | |
| printf("Yes, pop and send() one of them.\n"); | |
| peer->current_sending_byte = 0; | |
| } | |
| // Count bytes to send. | |
| len_to_send = sizeof(peer->sending_buffer) - peer->current_sending_byte; | |
| if (len_to_send > MAX_SEND_SIZE) | |
| len_to_send = MAX_SEND_SIZE; | |
| printf("Let's try to send() %zd bytes... ", len_to_send); | |
| send_count = send(peer->socket, (char *)&peer->sending_buffer + peer->current_sending_byte, len_to_send, 0); | |
| if (send_count < 0) { | |
| if (errno == EAGAIN || errno == EWOULDBLOCK) { | |
| printf("peer is not ready right now, try again later.\n"); | |
| } | |
| else { | |
| perror("send() from peer error"); | |
| return -1; | |
| } | |
| } | |
| // we have read as many as possible | |
| else if (send_count < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { | |
| break; | |
| } | |
| else if (send_count == 0) { | |
| printf("send()'ed 0 bytes. It seems that peer can't accept data right now. Try again later.\n"); | |
| break; | |
| } | |
| else if (send_count > 0) { | |
| peer->current_sending_byte += send_count; | |
| send_total += send_count; | |
| printf("send()'ed %zd bytes.\n", send_count); | |
| } | |
| } while (send_count > 0); | |
| printf("Total send()'ed %zu bytes.\n", send_total); | |
| return 0; | |
| } | |
| // common --------------------------------------------------------------------- | |
| /* Reads from stdin and create new message. This message enqueues to send queueu. */ | |
| int read_from_stdin(char *read_buffer, size_t max_len) | |
| { | |
| memset(read_buffer, 0, max_len); | |
| ssize_t read_count = 0; | |
| ssize_t total_read = 0; | |
| do { | |
| read_count = read(STDIN_FILENO, read_buffer, max_len); | |
| if (read_count < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { | |
| perror("read()"); | |
| return -1; | |
| } | |
| else if (read_count < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { | |
| break; | |
| } | |
| else if (read_count > 0) { | |
| total_read += read_count; | |
| if (total_read > max_len) { | |
| printf("Message too large and will be chopped. Please try to be shorter next time.\n"); | |
| fflush(STDIN_FILENO); | |
| break; | |
| } | |
| } | |
| } while (read_count > 0); | |
| size_t len = strlen(read_buffer); | |
| if (len > 0 && read_buffer[len - 1] == '\n') | |
| read_buffer[len - 1] = '\0'; | |
| printf("Read from stdin %zu bytes. Let's prepare message to send.\n", strlen(read_buffer)); | |
| return 0; | |
| } | |
| #endif /* MESSAGE_H */ |
| // Simple example of server with select() and multiple clients. | |
| #include <errno.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <sys/select.h> | |
| #include <sys/socket.h> | |
| #include <signal.h> | |
| #include <string.h> | |
| #include <fcntl.h> | |
| #include <netinet/in.h> | |
| #include <unistd.h> | |
| #include "message.h" | |
| #define MAX_CLIENTS 10 | |
| #define NO_SOCKET -1 | |
| #define SERVER_NAME "server" | |
| int listen_sock; | |
| peer_t connection_list[MAX_CLIENTS]; | |
| char read_buffer[1024]; // buffer for stdin | |
| void shutdown_properly(int code); | |
| void handle_signal_action(int sig_number) | |
| { | |
| if (sig_number == SIGINT) { | |
| printf("SIGINT was catched!\n"); | |
| shutdown_properly(EXIT_SUCCESS); | |
| } | |
| else if (sig_number == SIGPIPE) { | |
| printf("SIGPIPE was catched!\n"); | |
| shutdown_properly(EXIT_SUCCESS); | |
| } | |
| } | |
| int setup_signals() | |
| { | |
| struct sigaction sa; | |
| sa.sa_handler = handle_signal_action; | |
| if (sigaction(SIGINT, &sa, 0) != 0) { | |
| perror("sigaction()"); | |
| return -1; | |
| } | |
| if (sigaction(SIGPIPE, &sa, 0) != 0) { | |
| perror("sigaction()"); | |
| return -1; | |
| } | |
| return 0; | |
| } | |
| /* Start listening socket listen_sock. */ | |
| int start_listen_socket(int *listen_sock) | |
| { | |
| // Obtain a file descriptor for our "listening" socket. | |
| *listen_sock = socket(AF_INET, SOCK_STREAM, 0); | |
| if (*listen_sock < 0) { | |
| perror("socket"); | |
| return -1; | |
| } | |
| int reuse = 1; | |
| if (setsockopt(*listen_sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) != 0) { | |
| perror("setsockopt"); | |
| return -1; | |
| } | |
| struct sockaddr_in my_addr; | |
| memset(&my_addr, 0, sizeof(my_addr)); | |
| my_addr.sin_family = AF_INET; | |
| my_addr.sin_addr.s_addr = inet_addr(SERVER_IPV4_ADDR); | |
| my_addr.sin_port = htons(SERVER_LISTEN_PORT); | |
| if (bind(*listen_sock, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) != 0) { | |
| perror("bind"); | |
| return -1; | |
| } | |
| // start accept client connections | |
| if (listen(*listen_sock, 10) != 0) { | |
| perror("listen"); | |
| return -1; | |
| } | |
| printf("Accepting connections on port %d.\n", (int)SERVER_LISTEN_PORT); | |
| return 0; | |
| } | |
| void shutdown_properly(int code) | |
| { | |
| int i; | |
| close(listen_sock); | |
| for (i = 0; i < MAX_CLIENTS; ++i) | |
| if (connection_list[i].socket != NO_SOCKET) | |
| close(connection_list[i].socket); | |
| printf("Shutdown server properly.\n"); | |
| exit(code); | |
| } | |
| int build_fd_sets(fd_set *read_fds, fd_set *write_fds, fd_set *except_fds) | |
| { | |
| int i; | |
| FD_ZERO(read_fds); | |
| FD_SET(STDIN_FILENO, read_fds); | |
| FD_SET(listen_sock, read_fds); | |
| for (i = 0; i < MAX_CLIENTS; ++i) | |
| if (connection_list[i].socket != NO_SOCKET) | |
| FD_SET(connection_list[i].socket, read_fds); | |
| FD_ZERO(write_fds); | |
| for (i = 0; i < MAX_CLIENTS; ++i) | |
| if (connection_list[i].socket != NO_SOCKET && connection_list[i].send_buffer.current > 0) | |
| FD_SET(connection_list[i].socket, write_fds); | |
| FD_ZERO(except_fds); | |
| FD_SET(STDIN_FILENO, except_fds); | |
| FD_SET(listen_sock, except_fds); | |
| for (i = 0; i < MAX_CLIENTS; ++i) | |
| if (connection_list[i].socket != NO_SOCKET) | |
| FD_SET(connection_list[i].socket, except_fds); | |
| return 0; | |
| } | |
| int handle_new_connection() | |
| { | |
| struct sockaddr_in client_addr; | |
| memset(&client_addr, 0, sizeof(client_addr)); | |
| socklen_t client_len = sizeof(client_addr); | |
| int new_client_sock = accept(listen_sock, (struct sockaddr *)&client_addr, &client_len); | |
| if (new_client_sock < 0) { | |
| perror("accept()"); | |
| return -1; | |
| } | |
| char client_ipv4_str[INET_ADDRSTRLEN]; | |
| inet_ntop(AF_INET, &client_addr.sin_addr, client_ipv4_str, INET_ADDRSTRLEN); | |
| printf("Incoming connection from %s:%d.\n", client_ipv4_str, client_addr.sin_port); | |
| int i; | |
| for (i = 0; i < MAX_CLIENTS; ++i) { | |
| if (connection_list[i].socket == NO_SOCKET) { | |
| connection_list[i].socket = new_client_sock; | |
| connection_list[i].addres = client_addr; | |
| connection_list[i].current_sending_byte = -1; | |
| connection_list[i].current_receiving_byte = 0; | |
| return 0; | |
| } | |
| } | |
| printf("There is too much connections. Close new connection %s:%d.\n", client_ipv4_str, client_addr.sin_port); | |
| close(new_client_sock); | |
| return -1; | |
| } | |
| int close_client_connection(peer_t *client) | |
| { | |
| printf("Close client socket for %s.\n", peer_get_addres_str(client)); | |
| close(client->socket); | |
| client->socket = NO_SOCKET; | |
| dequeue_all(&client->send_buffer); | |
| client->current_sending_byte = -1; | |
| client->current_receiving_byte = 0; | |
| } | |
| /* Reads from stdin and create new message. This message enqueues to send queueu. */ | |
| int handle_read_from_stdin() | |
| { | |
| char read_buffer[DATA_MAXSIZE]; // buffer for stdin | |
| if (read_from_stdin(read_buffer, DATA_MAXSIZE) != 0) | |
| return -1; | |
| // Create new message and enqueue it. | |
| message_t new_message; | |
| prepare_message(SERVER_NAME, read_buffer, &new_message); | |
| print_message(&new_message); | |
| /* enqueue message for all clients */ | |
| int i; | |
| for (i = 0; i < MAX_CLIENTS; ++i) { | |
| if (connection_list[i].socket != NO_SOCKET) { | |
| if (peer_add_to_send(&connection_list[i], &new_message) != 0) { | |
| printf("Send buffer was overflowed, we lost this message!\n"); | |
| continue; | |
| } | |
| printf("New message to send was enqueued right now.\n"); | |
| } | |
| } | |
| return 0; | |
| } | |
| int handle_received_message(message_t *message) | |
| { | |
| printf("Received message from client.\n"); | |
| print_message(message); | |
| return 0; | |
| } | |
| int main(int argc, char **argv) | |
| { | |
| if (setup_signals() != 0) | |
| exit(EXIT_FAILURE); | |
| if (start_listen_socket(&listen_sock) != 0) | |
| exit(EXIT_FAILURE); | |
| /* Set nonblock for stdin. */ | |
| int flag = fcntl(STDIN_FILENO, F_GETFL, 0); | |
| flag |= O_NONBLOCK; | |
| fcntl(STDIN_FILENO, F_SETFL, flag); | |
| int i; | |
| for (i = 0; i < MAX_CLIENTS; ++i) { | |
| connection_list[i].socket = NO_SOCKET; | |
| create_peer(&connection_list[i]); | |
| } | |
| fd_set read_fds; | |
| fd_set write_fds; | |
| fd_set except_fds; | |
| int high_sock = listen_sock; | |
| printf("Waiting for incoming connections.\n"); | |
| while (1) { | |
| build_fd_sets(&read_fds, &write_fds, &except_fds); | |
| high_sock = listen_sock; | |
| for (i = 0; i < MAX_CLIENTS; ++i) { | |
| if (connection_list[i].socket > high_sock) | |
| high_sock = connection_list[i].socket; | |
| } | |
| int activity = select(high_sock + 1, &read_fds, &write_fds, &except_fds, NULL); | |
| switch (activity) { | |
| case -1: | |
| perror("select()"); | |
| shutdown_properly(EXIT_FAILURE); | |
| case 0: | |
| // you should never get here | |
| printf("select() returns 0.\n"); | |
| shutdown_properly(EXIT_FAILURE); | |
| default: | |
| /* All set fds should be checked. */ | |
| if (FD_ISSET(STDIN_FILENO, &read_fds)) { | |
| if (handle_read_from_stdin() != 0) | |
| shutdown_properly(EXIT_FAILURE); | |
| } | |
| if (FD_ISSET(listen_sock, &read_fds)) { | |
| handle_new_connection(); | |
| } | |
| if (FD_ISSET(STDIN_FILENO, &except_fds)) { | |
| printf("except_fds for stdin.\n"); | |
| shutdown_properly(EXIT_FAILURE); | |
| } | |
| if (FD_ISSET(listen_sock, &except_fds)) { | |
| printf("Exception listen socket fd.\n"); | |
| shutdown_properly(EXIT_FAILURE); | |
| } | |
| for (i = 0; i < MAX_CLIENTS; ++i) { | |
| if (connection_list[i].socket != NO_SOCKET && FD_ISSET(connection_list[i].socket, &read_fds)) { | |
| if (receive_from_peer(&connection_list[i], &handle_received_message) != 0) { | |
| close_client_connection(&connection_list[i]); | |
| continue; | |
| } | |
| } | |
| if (connection_list[i].socket != NO_SOCKET && FD_ISSET(connection_list[i].socket, &write_fds)) { | |
| if (send_to_peer(&connection_list[i]) != 0) { | |
| close_client_connection(&connection_list[i]); | |
| continue; | |
| } | |
| } | |
| if (connection_list[i].socket != NO_SOCKET && FD_ISSET(connection_list[i].socket, &except_fds)) { | |
| printf("Exception client fd.\n"); | |
| close_client_connection(&connection_list[i]); | |
| continue; | |
| } | |
| } | |
| } | |
| printf("And we are still waiting for clients' or stdin activity. You can type something to send:\n"); | |
| } | |
| return 0; | |
| } |
Is the file message.h available anywhere so that I can run this code?
thanks!
Is the file message.h available anywhere so that I can run this code?
thanks!
It's inside file common.h
How can I compile this code?
How can I compile this code?
Compile:-
gcc client.c -o client
gcc server.c -o server
Run:-
./server
./client 127.0.0.1
Before this, include common.h in both client.c and server.c
How can I compile this code?
replace "message.h" to "common.h" in client.c and server.c;
then run:
gcc client.c -o client
gcc server.c -o server
why you defined the functions in the header file
Is this implementation ever removing from the connection_list? If a peer exit, would it still be present in the connection_list?
Edit: reuse happen in line 151 of server.c code.
Why are the listen_sock and the client_sock not non_block?