介绍
C Liunx实现EchoServer非阻塞服务端(TPC协议)
支持库
#include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <sys/socket.h> #include <sys/time.h> #include <time.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdbool.h>
代码
typedef struct EchoServerInfo { int socketFD; struct sockaddr_in serverAddr; int bufferSize; struct timeval timeout; bool block; bool serverIsOpen; int clientFD; struct sockaddr_in clientAddr; } EchoServer; EchoServer *InitServer(); int LoadServer(EchoServer *server, int port, bool noBlock); void OpenServer(EchoServer *server); void HandleServerConnect(EchoServer *server); char *GetClientDate(EchoServer *server, bool fastRead); char *GetClientIP(EchoServer *server); int SendClientDate(EchoServer *server, char *date); void SetServerTimeout(EchoServer *server, int s, int us); void CloseServer(EchoServer *server); void FreeServer(EchoServer *server); EchoServer *InitServer() { EchoServer *result = (EchoServer *)malloc(sizeof(EchoServer)); if (result != NULL) { memset(result, 0, sizeof(EchoServer)); result->socketFD = 0; result->clientFD = 0; result->bufferSize = 1024; result->serverIsOpen = false; SetServerTimeout(result, 3, 0); } return result; } int LoadServer(EchoServer *server, int port, bool noBlock) { // 创建信箱 server->socketFD = socket(AF_INET, SOCK_STREAM, 0); if (server->socketFD < 0) { return -1; } if (noBlock) { int flags = fcntl(server->socketFD, F_GETFL, 0); fcntl(server->socketFD, F_SETFL, flags | O_NONBLOCK); } server->block = !noBlock; server->serverAddr.sin_family = AF_INET; server->serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); server->serverAddr.sin_port = htons(port); if (bind(server->socketFD, (struct sockaddr *)&server->serverAddr, sizeof(server->serverAddr)) < 0) return -2; if (listen(server->socketFD, port) < 0) return -3; } void OpenServer(EchoServer *server) { socklen_t clientAddrLen; clock_t start, end; bool block = server->block; server->serverIsOpen = true; while (server->serverIsOpen) { if (block) start = clock(); clientAddrLen = sizeof(server->clientAddr); server->clientFD = accept(server->socketFD, (struct sockaddr *)&server->clientAddr, &clientAddrLen); if (block) end = clock(); if (server->clientFD > 0) { HandleServerConnect(server); close(server->clientFD); continue; } if (block) usleep((end - start) / CLOCKS_PER_SEC); } } int SendClientDate(EchoServer *server, char *date) { struct timeval timeout = server->timeout; fd_set wait; FD_ZERO(&wait); FD_SET(server->clientFD, &wait); if (select(server->clientFD + 1, NULL, &wait, NULL, &timeout) > 0) return write(server->clientFD, date, strlen(date)); else return -1; } char *GetClientDate(EchoServer *server, bool fastRead) { int len, ready, size = 1; char *temp; char *result = (char *)malloc(sizeof(char)); char *buffer = (char *)malloc(sizeof(char) * server->bufferSize); if (!result) return ""; else result[0] = '\0'; if (!buffer) return ""; else buffer[0] = '\0'; struct timeval timeout = server->timeout; fd_set wait; FD_ZERO(&wait); FD_SET(server->clientFD, &wait); while (true) { if (server->block) goto ReadMessage; ready = select(server->clientFD + 1, &wait, NULL, NULL, &timeout); if (ready > 0) { if (FD_ISSET(server->clientFD, &wait)) { ReadMessage: len = read(server->clientFD, buffer, server->bufferSize - 1); if (len > 0) { size += len; buffer[len] = '\0'; temp = (char *)realloc(result, sizeof(char) * size); if (!temp) break; strcpy(temp, result); result = temp; strcat(result, buffer); if (server->block) continue; if (len < server->bufferSize - 1 && fastRead) break; } else break; } } else break; } free(buffer); return result; } char *GetClientIP(EchoServer *server) { char *clientIP = (char *)malloc(INET_ADDRSTRLEN); if (clientIP == NULL) return NULL; struct sockaddr_in *pV4Addr = &server->clientAddr; if (inet_ntop(AF_INET, &(pV4Addr->sin_addr), clientIP, INET_ADDRSTRLEN) == NULL) { free(clientIP); return NULL; } return clientIP; } void SetServerTimeout(EchoServer *server, int s, int us) { server->timeout.tv_sec = s; server->timeout.tv_usec = us; } void CloseServer(EchoServer *server) { if (server->socketFD) close(server->socketFD); server->serverIsOpen = false; } void FreeServer(EchoServer *server) { free(server); }
这里的void HandleServerConnect(EchoServer *server)只有申明没有定义,每当有连接建立时自动调用此函数
示例
#include "EchoServer.h" //这里别忘记改掉 #include <stdio.h> void HandleServerConnect(EchoServer *server) { char *ip = GetClientIP(server); char *date = GetClientDate(server, true); int len; printf("%s 来自IP:%s \n", date, ip); len = SendClientDate(server, "close"); //CloseServer(server); } int main() { EchoServer *server = InitServer(); if (LoadServer(server, 1001, false) == 0) { OpenServer(server); } FreeServer(server); }
文章有(1)条网友点评
这个代码有问题,在读取的时候容易出错,就当作参考吧