介绍
C Liunx实现EchoServer非阻塞服务端(TPC协议)
客户端实现在:http://t.csdnimg.cn/vmQpV
支持库
#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);
}