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

#define ERR_EXIT(m)                        \
            do                             \
            {                              \
                perror(m);                 \
                exit(EXIT_FAILURE);        \
                                           \
            }while(0)

struct packet
{
    int len;
    char buf[1024];
};

void sig(int num)
{
    switch (num)
    {
    case SIGUSR1:
        printf("client recv signal %d, exit...\n", num);
        exit(0);
        break;
    default:
        break;

    }

}

ssize_t readn(int fd, void *buf, size_t count)
{
    size_t nleft = count;
    ssize_t nread;
    char *bufp = (char*)buf;

    while (nleft > 0)
    {
        if ((nread = read(fd, bufp, nleft)) < 0)
        {
            if (errno == EINTR)
                continue;
            return -1;
        }
        else if (nread == 0) //若对方已关闭
            return count - nleft;

        bufp += nread;
        nleft -= nread;
    }

    return count;
}

ssize_t writen(int fd, const void *buf, size_t count)
{
    size_t nleft = count;
    ssize_t nwritten;
    char *bufp = (char*)buf;

    while (nleft > 0)
    {
        if ((nwritten = write(fd, bufp, nleft)) < 0)
        {
            if (errno == EINTR)
                continue;
            return -1;
        }
        else if (nwritten == 0)
            continue;

        bufp += nwritten;
        nleft -= nwritten;
    }

    return count;

}

void read_service (int conn)
{
    struct packet recvbuf;
    int n;
    while (1)
    {
        memset(&recvbuf, 0, sizeof(recvbuf));
        int ret = readn(conn, &recvbuf.len, 4);
        if (ret == -1)
            ERR_EXIT("read failed");
        else if (ret < 4)
        {
            printf("server close\n");
            break;
        }

        n = ntohl(recvbuf.len);
        ret = readn(conn, recvbuf.buf, n);
        if (ret == -1)
            ERR_EXIT("read");
        else if (ret < n)
        {
            printf("server close\n");
            break;
        }

        fputs(recvbuf.buf, stdout);

    }

    return ;
}

void write_service (int conn)
{
    struct packet sendbuf;
    int n;
    while (1)
    {

        memset(&sendbuf, 0, sizeof(sendbuf));
        if (fgets(sendbuf.buf, sizeof(sendbuf.buf), stdin) == NULL)
            ERR_EXIT("fgets failed");

        n = strlen(sendbuf.buf);
        sendbuf.len = htonl(n);
        writen(conn, &sendbuf, 4 + n);

    }

    close(conn);
    return ;
}

int main()
{

    int sockfd;

    //建立socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    if (sockfd == -1)
    {
        perror("create socket failed");
        return 1;
    }

    //connect 连接server
    struct sockaddr_in serveraddr_in;
    memset(&serveraddr_in, 0, sizeof(serveraddr_in));

    serveraddr_in.sin_family = AF_INET;
    serveraddr_in.sin_port = htons(12345);   /* port in network byte order */
    serveraddr_in.sin_addr.s_addr = inet_addr("127.0.0.1");

    if ( connect(sockfd, (struct sockaddr *)&serveraddr_in, sizeof(serveraddr_in) ) == -1)
    {
        perror("connect failed");
        return 1;
    }

    if ( signal(SIGUSR1, sig) == SIG_ERR )
    {
        perror("install signal error");
    }

    int pid = fork();

    if (pid == 0)
    {
        //业务
        while (1)
        {
            read_service(sockfd);
            kill(getppid(), SIGUSR1);
            close(sockfd);
            exit (1);

        }

    }
    else
    {
        write_service(sockfd);

    }

    return 0;
}


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

#define ERR_EXIT(m)                        \
            do                             \
            {                              \
                perror(m);                 \
                exit(EXIT_FAILURE);        \
                                           \
            }while(0)

/*

 struct sockaddr {
               sa_family_t sa_family;
               char        sa_data[14];
           }

 struct sockaddr_in {
               sa_family_t    sin_family;
               in_port_t      sin_port;
               struct in_addr sin_addr;
           };

 struct in_addr {
               uint32_t       s_addr;
           };

*/

/*

    typedef void (*sighandler_t)(int);

    sighandler_t signal(int signum, sighandler_t handler);

*/
struct packet
{
    int len;
    char buf[1024];
};

void sig(int num)
{
    switch (num)
    {
    case SIGUSR1:
        printf("server recv signal %d, exit...\n", num);
        exit(1);
        break;
    default:
        break;

    }

}

ssize_t readn(int fd, void *buf, size_t count)
{
    size_t nleft = count;
    ssize_t nread;
    char *bufp = (char*)buf;

    while (nleft > 0)
    {
        if ((nread = read(fd, bufp, nleft)) < 0)
        {
            if (errno == EINTR)
                continue;
            return -1;
        }
        else if (nread == 0) //若对方已关闭
            return count - nleft;

        bufp += nread;
        nleft -= nread;
    }

    return count;
}

ssize_t writen(int fd, const void *buf, size_t count)
{
    size_t nleft = count;
    ssize_t nwritten;
    char *bufp = (char*)buf;

    while (nleft > 0)
    {
        if ((nwritten = write(fd, bufp, nleft)) < 0)
        {
            if (errno == EINTR)
                continue;
            return -1;
        }
        else if (nwritten == 0)
            continue;

        bufp += nwritten;
        nleft -= nwritten;
    }

    return count;

}

void read_service (int conn)
{
    struct packet recvbuf;
    int n;
    while (1)
    {
        memset(&recvbuf, 0, sizeof(recvbuf));
        int ret = readn(conn, &recvbuf.len, 4);
        if (ret == -1)
            ERR_EXIT("read failed");
        else if (ret < 4)
        {
            printf("client close\n");
            break;
        }

        n = ntohl(recvbuf.len);
        ret = readn(conn, recvbuf.buf, n);
        if (ret == -1)
            ERR_EXIT("read");
        else if (ret < n)
        {
            printf("client close\n");
            //printf("\n\nclient %s:%d  disconn\n\n", inet_ntoa(clientaddr_in.sin_addr), ntohs(clientaddr_in.sin_port));
            break;
        }

        fputs(recvbuf.buf, stdout);

    }

    return ;
}

void write_service (int conn)
{
    struct packet sendbuf;
    int n;
    while (1)
    {

        memset(&sendbuf, 0, sizeof(sendbuf));
        if (fgets(sendbuf.buf, sizeof(sendbuf.buf), stdin) == NULL)
            ERR_EXIT("fgets failed");

        n = strlen(sendbuf.buf);
        sendbuf.len = htonl(n);
        writen(conn, &sendbuf, 4 + n);

    }

    close(conn);
    return ;
}

int main()
{

    int serverfd;

    //建立socket
    serverfd = socket(AF_INET, SOCK_STREAM, 0);

    if (serverfd == -1)
    {
        perror("create socket failed");
        return 1;
    }

    //给TCP设置地址可重用
    int on = 1;
    if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
    {
        printf("setsockopt failed %s\n", strerror(errno));
        return EXIT_FAILURE;
    }

    //bind 绑定端口,IP
    struct sockaddr_in serveraddr_in;
    memset(&serveraddr_in, 0, sizeof(serveraddr_in));

    serveraddr_in.sin_family = AF_INET;
    serveraddr_in.sin_port = htons(12345);   /* port in network byte order */
    serveraddr_in.sin_addr.s_addr = inet_addr("0.0.0.0");

    if ( bind(serverfd, (struct sockaddr *)&serveraddr_in, sizeof(serveraddr_in)) == -1)
    {
        perror("bind failed");
        return 1;
    }

    //listen 被动套接字,监听端口
    if (listen(serverfd, 20) == -1)
    {
        perror("listen failed");
        return 1;
    }

    //while(1)
    {

        //accept 阻塞等待client连接

        int clientfd = -1;
        struct sockaddr_in clientaddr_in;

        memset(&clientaddr_in, 0, sizeof(clientaddr_in));
        socklen_t clientaddr_len = sizeof(clientaddr_in);
        if ( (clientfd = accept(serverfd, (struct sockaddr *)&clientaddr_in, &clientaddr_len) ) == -1)
        {
            perror("accept failed");
            return 1;
        }
        else
        {
            printf("\n\nclient %s:%d  connected\n\n", inet_ntoa(clientaddr_in.sin_addr), ntohs(clientaddr_in.sin_port));
        }

        if ( signal(SIGUSR1, sig) == SIG_ERR )
        {
            perror("install signal error");
        }

        int pid = fork();

        if (pid == 0)
        {
            //子进程关闭被动套接字
            close(serverfd);

            //业务
            while (1)
            {
                read_service(clientfd);
                kill(getppid(), SIGUSR1);
                close(clientfd);
                exit (1);
            }

        }
        else
        {

            write_service(clientfd);

        }
    }

    return 0;
}


备份地址: 【Socket PRGM: chat_p2p