一、技术简介

 (1)服务端打开两个端口9999和6666监听外来连接;

 (2)服务端的子进程通过端口9999监听外来消息,通过端口6666发送消息;

 (3)客户端的子进程处理外来消息,父进程发送消息

二、服务器程序

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/un.h>

#define SERV_PORT1 9999
#define SERV_PORT2 6666
#define MAXLINE 4096

#define SA struct sockaddr

void send_msg(int);
void listen_msg(int, const struct sockaddr*);
char *sock_ntop(const struct sockaddr*, socklen_t);

int main(int argc, char *argv[]) {
    int listenfd1, connfd1;
    int listenfd2, connfd2;
    pid_t childpid;
    socklen_t clilen1, clilen2;
    struct sockaddr_in servaddr1, servaddr2;
    struct sockaddr_in cliaddr1, cliaddr2;

    listenfd1 = socket(AF_INET, SOCK_STREAM, 0);
    listenfd2 = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr1, sizeof(servaddr1));
    servaddr1.sin_family = AF_INET;
    servaddr1.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr1.sin_port = htons(SERV_PORT1);

    bzero(&servaddr2, sizeof(servaddr2));
    servaddr2.sin_family = AF_INET;
    servaddr2.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr2.sin_port = htons(SERV_PORT2);

    bind(listenfd1, (SA *)&servaddr1, sizeof(servaddr1));
    bind(listenfd2, (SA *)&servaddr2, sizeof(servaddr2));

    listen(listenfd1, 1);
    listen(listenfd2, 1);

    clilen1 = sizeof(cliaddr1);
    clilen2 = sizeof(cliaddr2);
    connfd1 = accept(listenfd1, (SA *)&cliaddr1, &clilen1);
    connfd2 = accept(listenfd2, (SA *)&cliaddr2, &clilen2);

    if (connfd1 && connfd2) {
        if ( (childpid = fork()) == 0) {
          close(listenfd2);
          close(connfd2);
          close(listenfd1);
          listen_msg(connfd1, (SA *)&cliaddr1);
          close(connfd1);
          exit(0);
      }
      close(listenfd1);
      close(connfd1);
      close(listenfd2);
      send_msg(connfd2);
      close(connfd2);
    }
    exit(0);
}

void listen_msg(int sockfd, const struct sockaddr *addr) {
    ssize_t n;
    char buf[MAXLINE];

    while ( (n = read(sockfd, buf, MAXLINE)) > 0) {
      printf("[%s]: ", sock_ntop(addr, sizeof(addr)));
      fputs(buf, stdout);
      bzero(buf, sizeof(buf));
    }
}

void send_msg(int sockfd) {
    char buf[MAXLINE];

    while (fgets(buf, MAXLINE, stdin) != NULL) {
        write(sockfd, buf, sizeof(buf));    
    }
}

char *sock_ntop(const struct sockaddr *sa, socklen_t salen) {

    char portstr[8];
    static char str[128];

    switch (sa->sa_family) {
        case AF_INET: {
            struct sockaddr_in    *sin = (struct sockaddr_in *) sa;

            if (inet_ntop(AF_INET, &sin->sin_addr, str,
                sizeof(str)) == NULL) {
                return(NULL);
            }
            if (ntohs(sin->sin_port) != 0) {
                snprintf(portstr, sizeof(portstr), ":%d",
                ntohs(sin->sin_port));
                strcat(str, portstr);
            }
            return(str);
        }
        case AF_INET6: {
            struct sockaddr_in6    *sin6 = (struct sockaddr_in6 *) sa;

            str[0] = '[';
            if (inet_ntop(AF_INET6, &sin6->sin6_addr, str + 1,
                sizeof(str) - 1) == NULL) {
                return(NULL);
            }
            if (ntohs(sin6->sin6_port) != 0) {
                snprintf(portstr, sizeof(portstr), "]:%d",
                ntohs(sin6->sin6_port));
                strcat(str, portstr);
                return(str);
            }
            return (str + 1);
        }
        case AF_UNIX: {
            struct sockaddr_un    *unp = (struct sockaddr_un *) sa;

            if (unp->sun_path[0] == 0) {
                strcpy(str, "(no pathname bound)");
            } else {
                snprintf(str, sizeof(str), "%s", unp->sun_path);
            }
            return(str);
        }
        default: {
            snprintf(str, sizeof(str), "sock_ntop: unknown AF_xxx: %d, len %d",
                 sa->sa_family, salen);
            return(str);
        }
    }
    return (NULL);
}

三、客户端程序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/un.h>

#define SA struct sockaddr
#define SERV_PORT1 9999
#define SERV_PORT2 6666
#define MAXLINE 4096

void send_msg(int);
void listen_msg(int, const struct sockaddr*);
char *sock_ntop(const struct sockaddr*, socklen_t);

int main(int argc, char *argv[]) {
    pid_t childpid;
    int sockfd1,sockfd2;
    int connstatus1, connstatus2;
    struct sockaddr_in servaddr1, servaddr2;

    if (argc != 2) {
        printf("usage: %s <IPaddress>\n", argv[0]);
        exit(0);
    }
    
    sockfd1 = socket(AF_INET, SOCK_STREAM, 0);
    sockfd2 = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr1, sizeof(servaddr1));
    servaddr1.sin_family = AF_INET;
    servaddr1.sin_port = htons(SERV_PORT1);
    inet_pton(AF_INET, argv[1], &servaddr1.sin_addr);

    bzero(&servaddr2, sizeof(servaddr2));
    servaddr2.sin_family = AF_INET;
    servaddr2.sin_port = htons(SERV_PORT2);
    inet_pton(AF_INET, argv[1], &servaddr2.sin_addr);

    connstatus1 = connect(sockfd1, (SA *)&servaddr1, sizeof(servaddr1));
    connstatus2 = connect(sockfd2, (SA *)&servaddr2, sizeof(servaddr2));

    if (connstatus1 == 0 && connstatus2 == 0) {
        if ( (childpid = fork()) == 0) {
          close(sockfd1);
          listen_msg(sockfd2, (SA *)&servaddr2);
          close(sockfd2);
          exit(0);
      }
      close(sockfd2);
      send_msg(sockfd1);
      close(sockfd1);
    } else {
        printf("connect failed!\n");
    }
    exit(0);
}

void listen_msg(int sockfd, const struct sockaddr *addr) {
    ssize_t n;
    char buf[MAXLINE];

    while ( (n = read(sockfd, buf, MAXLINE)) > 0) {
       printf("[%s]: ", sock_ntop(addr, sizeof(addr)));
        fputs(buf, stdout);
        bzero(buf, sizeof(buf));
    }
}

void send_msg(int sockfd) {
    char buf[MAXLINE];

    while (fgets(buf, MAXLINE, stdin) != NULL) {
        write(sockfd, buf, sizeof(buf));
    }
}

char *sock_ntop(const struct sockaddr *sa, socklen_t salen) {
    
    char portstr[8];    
    static char str[128];
   
    switch (sa->sa_family) {
        case AF_INET: {
            struct sockaddr_in    *sin = (struct sockaddr_in *) sa;

            if (inet_ntop(AF_INET, &sin->sin_addr, str, 
                sizeof(str)) == NULL) {
                return(NULL);
            }
            if (ntohs(sin->sin_port) != 0) {
                snprintf(portstr, sizeof(portstr), ":%d", 
                    ntohs(sin->sin_port));
                strcat(str, portstr);
            }
            return(str);
        }
        case AF_INET6: {
            struct sockaddr_in6    *sin6 = (struct sockaddr_in6 *) sa;

            str[0] = '[';
            if (inet_ntop(AF_INET6, &sin6->sin6_addr, str + 1, 
                sizeof(str) - 1) == NULL) {
                return(NULL);
            }
            if (ntohs(sin6->sin6_port) != 0) {
                snprintf(portstr, sizeof(portstr), "]:%d",
                    ntohs(sin6->sin6_port));
                strcat(str, portstr);
                return(str);
            }
            return (str + 1);
        }
        case AF_UNIX: {
            struct sockaddr_un    *unp = (struct sockaddr_un *) sa;

            if (unp->sun_path[0] == 0) {
                strcpy(str, "(no pathname bound)");
            } else {
                snprintf(str, sizeof(str), "%s", unp->sun_path);
            }
            return(str);
        }
        default: {
            snprintf(str, sizeof(str), "sock_ntop: unknown AF_xxx: %d, len %d",
                 sa->sa_family, salen);
            return(str);
        }
    }
    return (NULL);
}