Linux下实现简单Echo中继服务器

来源:互联网 发布:java boolean几个字节 编辑:程序博客网 时间:2024/05/17 08:48

Linux下编写一个Echo中继服务器,echo客户端通过它获取Echo服务器的响应。中继服务器能同时作为多个echo服务器的中继,并且具有一个简单的负载均衡算法。

1. 服务器与客户端描述与设计
支持多个服务器进行Echo服务,服务器需要设定输入端口参数,服务器和客户端可以直接使用多进程版本的设计即可。

2. 中继服务器描述与设计
为了简化,假定所有的服务器都在相同的ip地址上,而使用不同的端口,中继服务器只需要一个ip和多个端口参数的输入。
当客户端连接时,中继服务器Accept之后,开启新的进程A,进程A向使用负载均衡算法找出的Echo服务器申请连接,连接成功之后,进程A创建工作线程P。进程A的主线程接收从客户端发来的信息并发给Echo服务器,工作线程P接收从Echo服务器发来的信息并发给客户端。
这样设计是为了当客户端退出时,能够关闭socket连接,正常退出程序。
对于中继服务器还需要考虑负载均衡的,现使用最简单的算法,即在中继服务器维护一个“下次连接服务器号”,每次有客户端连接,就使用这个号码找到应该连接的服务器,然后这个号加1。

3. 端口规定
中继服务器在9000端口监听客户端的连接;
服务器在给定的端口监听中继服务器的连接。

完整代码如下:
1. 中继器

// recpeater.c#include "unp.h" #define BUFFER_SIZE BUFFSIZE#define SERVPORT 9000#define BACKLOG 20 #define MAX_SERVER 10 char buffer_c[BUFFER_SIZE];char buffer_s[BUFFER_SIZE];int serAmount;int port[MAX_SERVER];int portCurrent;char *serIp; typedef struct m_socket {    int s_server;    int s_client;} m_socket, * pm_socket; void str_send_2_server(int s_server, int s_client,         char* buf) {    size_t n;     while (1) {        n = Read(s_client, buf,             BUFFER_SIZE);        if (n <= 0)            return; /* EOF */         Write(s_server, buf, n);    } } void* str_echo_2_client(void *arg) {    size_t n;    int s_client = ((pm_socket)arg)->s_client;    int s_server = ((pm_socket)arg)->s_server;     while (1)   {        n = Read(s_server, buffer_c,             BUFFER_SIZE);         if (n <= 0)            return; /* EOF */         Write(s_client, buffer_c, n);    } } void str_echo_via_repeater(int s_client) {    int     s_server, ret;    struct sockaddr_in servaddr;     s_server = Socket(AF_INET, SOCK_STREAM, 0);     bzero(&servaddr, sizeof(servaddr));    servaddr.sin_family = AF_INET;    servaddr.sin_port = htons(port[portCurrent]);    Inet_pton(AF_INET, serIp, &servaddr.sin_addr);     Connect(s_server, (struct sockaddr *) &servaddr,         sizeof(servaddr));     pthread_t tid;    m_socket socket;    socket.s_client = s_client;    socket.s_server = s_server;     Pthread_create(&tid, NULL, str_echo_2_client,         (void *) &socket);     str_send_2_server(s_server, s_client, buffer_s);     Shutdown(s_server, 2);    Shutdown(s_client, 2);     Close(s_server);    Close(s_client);} void sig_chld(int signo) {    pid_t    pid;    int      stat;     while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)        printf("child %d terminated\n", pid);    return;} int main(int argc, char *argv[]) {    int     listenfd, connfd;    size_t  clilen;    struct sockaddr_in cliaddr, servaddr;    int i;         if (argc < 3 || argc > MAX_SERVER + 2) {        printf("usage: repeater IP port1 [port2 port3 ... port10]\n");        return 1;    }     serIp = argv[1];     serAmount = argc - 2;    for (i=0; i<serAmount; i++)        port[i] = atoi(argv[i+2]);     portCurrent = 0;     signal(SIGCHLD, sig_chld);     listenfd = Socket(AF_INET, SOCK_STREAM, 0);     bzero(&servaddr, sizeof(servaddr));    servaddr.sin_family = AF_INET;    servaddr.sin_addr.s_addr = htonl (INADDR_ANY);    servaddr.sin_port = htons(SERVPORT);    Bind(listenfd, (struct sockaddr *) &servaddr,         sizeof(servaddr));     Listen(listenfd, BACKLOG);         while (1) {        clilen = sizeof(cliaddr);        connfd = Accept(listenfd,             (struct sockaddr *) &cliaddr,             &clilen);        if (connfd < 0 && connfd == EINTR)            continue;        if (Fork() == 0) {            Close(listenfd);            str_echo_via_repeater(connfd);            return 0;        }         // 实现负载均衡算法        portCurrent = (++portCurrent % serAmount);         Close(connfd);      }    return 0;}

2. 服务器
// ser.c#include "unp.h" #define BUFFER_SIZE BUFFSIZE//#define SERVPORT 9993#define BACKLOG 20 char buffer[BUFFER_SIZE]; void str_echo2(int sockfd, char* buf) {    ssize_t n;     while (1) {        n = Read(sockfd, buf, BUFFER_SIZE);         if (n > 0)            Write(sockfd, buf, n);        else            return;    }} void sig_chld(int signo) {    pid_t    pid;    int      stat;     while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)        printf("child %d terminated\n", pid);    return;} int main(int argc, char *argv[]) {    int     listenfd, connfd;    size_t  clilen;    struct sockaddr_in cliaddr, servaddr;    int SERVPORT;         if (argc != 2) {        printf("usage: ser PORT\n");        return 1;    }     SERVPORT = atoi(argv[1]);     signal(SIGCHLD, sig_chld);     listenfd = Socket(AF_INET, SOCK_STREAM, 0);     bzero(&servaddr, sizeof(servaddr));    servaddr.sin_family = AF_INET;    servaddr.sin_addr.s_addr = htonl (INADDR_ANY);    servaddr.sin_port = htons(SERVPORT);    Bind(listenfd, (struct sockaddr *) &servaddr,         sizeof(servaddr));     Listen(listenfd, BACKLOG);         while (1) {        clilen = sizeof(cliaddr);        connfd = Accept(listenfd,             (struct sockaddr *) &cliaddr,             &clilen);        if (connfd < 0 && connfd == EINTR)            continue;        if (Fork() ==0) {            Close(listenfd);            str_echo2(connfd, buffer);             Close(connfd);             return 0;        }        Close(connfd);      }    return 0;}

3. 客户端
// cln.c#include "unp.h" #define BUFFER_SIZE BUFFSIZE#define SERVPORT 9000#define BACKLOG 20 char sbuffer[BUFFER_SIZE];char rbuffer[BUFFER_SIZE]; void str_cli1(int infd, int outfd, int sockfd) {    size_t n;     while (1) {        n = Read(infd, sbuffer, BUFFER_SIZE);        if (n <= 0)            return; /* EOF */         Write(sockfd, sbuffer, n);        n = Read(sockfd, rbuffer, BUFFER_SIZE);        if (n <= 0)            return; /* FIN */        Write(outfd, rbuffer, n);    } } int main(int argc, char *argv[]) {    int     sockfd, ret;    struct sockaddr_in servaddr;     if (argc != 2) {        printf("usage: cln IP\n");        return 1;    }     sockfd = Socket(AF_INET, SOCK_STREAM, 0);     bzero(&servaddr, sizeof(servaddr));    servaddr.sin_family = AF_INET;    servaddr.sin_port = htons(SERVPORT);    Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);     Connect(sockfd, (struct sockaddr *) &servaddr,         sizeof(servaddr));    str_cli1(fileno(stdin), fileno(stdout),         sockfd);     /* do it all */    Close(sockfd);         return 0;}


0 0
原创粉丝点击