?? udp_chat_server.c
字號:
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/select.h>#include <sys/time.h>#include <arpa/inet.h>#include <string.h>#include <errno.h>#include "utils.h"#include "link.h"//////////////////////////////////////////////////////////////////////// Macro definitions//////////////////////////////////////////////////////////////////////#define BUFFER_SIZE 1024//////////////////////////////////////////////////////////////////////// Global variables//////////////////////////////////////////////////////////////////////int global_chat_service_socket;fd_set global_read_set;fd_set global_write_set;fd_set global_except_set;int global_max_fd = 0;link_t *global_client_links;//////////////////////////////////////////////////////////////////////// Function prototypes//////////////////////////////////////////////////////////////////////void network_init(void);void network_register_read(int fd);void network_register_write(int fd);void network_register_except(int fd);void network_unregister_read(int fd);void network_unregister_write(int fd);void network_unregister_except(int fd);void data_exchange(char *message, unsigned long length);static void local_destroy_data(void *p);static void local_dump_node(void *p);//////////////////////////////////////////////////////////////////////// Functions//////////////////////////////////////////////////////////////////////int main(int argc, char **argv){ if (argc < 3) { fprintf(stdout, "Usage: %s <ip> <port>\n", argv[0]); exit(1); } global_client_links = link_init(local_destroy_data, local_dump_node); // XXX:step 1, socket(); //int socket(int domain, int type, int protocol); if ((global_chat_service_socket = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { fprintf(stderr, "Create a new UDP socket failed: %s\n", strerror(errno)); exit(1); } // XXX:step 2, bind(); struct sockaddr_in server_address; memset(&server_address, 0, sizeof(server_address)); server_address.sin_family = PF_INET; server_address.sin_port = htons(atoi(argv[2])); server_address.sin_addr.s_addr = inet_addr(argv[1]); // int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen); if (bind(global_chat_service_socket, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) { fprintf(stderr, "bind() failed: %s\n", strerror(errno)); exit(1); } network_init(); network_register_read(global_chat_service_socket); fd_set rset, wset, eset; int n; struct timeval to; for (;;) { rset = global_read_set; wset = global_write_set; eset = global_except_set; to.tv_sec = 1; to.tv_usec = 0; // XXX:step 3, recvfrom()/sendto //int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); if ((n = select(global_max_fd + 1, &rset, &wset, &eset, &to)) < 0) { if (errno == EINTR) { continue; } else { fprintf(stderr, "select() failed: %s\n", strerror(errno)); // FIXME: } } else if (n == 0) { // TODO: do something here. fprintf(stdout, "timeout ...\n"); } else { if (FD_ISSET(global_chat_service_socket, &rset)) { char buffer[BUFFER_SIZE]; struct sockaddr_in peer_address; socklen_t peer_address_length; ssize_t n; peer_address_length = sizeof(peer_address); again: // ssize_t recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen); if ((n = recvfrom(global_chat_service_socket, buffer, BUFFER_SIZE, 0, (struct sockaddr *) &peer_address, &peer_address_length)) < 0) { if (errno == EINTR) { goto again; } else { fprintf(stderr, "recvfrom() failed: %s\n", strerror(errno)); // FIXME: error handler } } else { fprintf(stdout, "INFO: read %d bytes from %s:%d\n", n, inet_ntoa(peer_address.sin_addr), ntohs(peer_address.sin_port));#if 0 int i; for (i = 0; i < n; i++) { fprintf(stdout, "0x%x", buffer[i]); }#endif buffer[n] = '\0'; fprintf(stdout, "DEBUG: %s\n", buffer); link_node_t *node; node = create_node(NODE_TYPE_NORMAL); if ((node->data = (void *) malloc(sizeof(struct sockaddr_in))) == NULL) { fprintf(stderr, "Allocate memory failed: %s\n", strerror(errno)); // FIXME: error handler } else { // FIXME: check existed client object *((struct sockaddr_in *) node->data) = peer_address; } link_insert_node(global_client_links, global_client_links, node, INSERT_METHOD_AFTER); data_exchange(buffer, n); } } } } // XXX: step 4, close() close(global_chat_service_socket); link_destroy(global_client_links); return 0;}void data_exchange(char *message, unsigned long length){ link_node_t *p; link_node_t *current; p = global_client_links; link_dump_nodes(global_client_links); struct sockaddr_in peer_address; while (p && p->next) { current = p; p = current->next; fprintf(stdout, "DEBUG: current = %p, current->type = %d\n", current, current->type); if (current->type == NODE_TYPE_NORMAL) { // FIXME: check return value peer_address = *(struct sockaddr_in *) current->data; // ssize_t sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen); sendto(global_chat_service_socket, message, length, 0, (struct sockaddr *) &peer_address, sizeof(peer_address)); fprintf(stdout, "forwarding data to %s:%d\n", inet_ntoa(peer_address.sin_addr), ntohs(peer_address.sin_port)); } } if (p->type == NODE_TYPE_NORMAL) { peer_address = *(struct sockaddr_in *) p->data; // FIXME: check return value // ssize_t sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen); sendto(global_chat_service_socket, message, length, 0, (struct sockaddr *) &peer_address, sizeof(peer_address)); fprintf(stdout, "forwarding data to %s:%d\n", inet_ntoa(peer_address.sin_addr), ntohs(peer_address.sin_port)); }}void network_init(void){ FD_ZERO(&global_read_set); FD_ZERO(&global_write_set); FD_ZERO(&global_except_set); global_max_fd = 0;}void network_register_read(int fd){ //void FD_SET(int fd, fd_set * fdset); FD_SET(fd, &global_read_set); if (fd > global_max_fd) { global_max_fd = fd; }}void network_unregister_read(int fd){ FD_CLR(fd, &global_read_set);}void network_register_write(int fd){ //void FD_SET(int fd, fd_set * fdset); FD_SET(fd, &global_write_set); if (fd > global_max_fd) { global_max_fd = fd; }}void network_unregister_write(int fd){ FD_CLR(fd, &global_write_set);}void network_register_except(int fd){ //void FD_SET(int fd, fd_set * fdset); FD_SET(fd, &global_except_set); if (fd > global_max_fd) { global_max_fd = fd; }}void network_unregister_except(int fd){ FD_CLR(fd, &global_except_set);}static void local_destroy_data(void *p){ safe_free(p);}static void local_dump_node(void *p){ if (!p) { return; } fprintf(stdout, "DEBUG: try to dump %p\n", p); link_node_t *node = (link_node_t *) p; if (get_node_type(node) == NODE_TYPE_HEAD) { //fprintf(stdout, "HEAD:\n"); } else if (get_node_type(node) == NODE_TYPE_TAIL) { //fprintf(stdout, "TAIL:\n"); } else { struct sockaddr_in peer_address; peer_address = *(struct sockaddr_in *) node->data; fprintf(stdout, "Normal: %s:%d\n", inet_ntoa(peer_address.sin_addr), ntohs(peer_address.sin_port)); }}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -