socket編程之點對點聊天程序

點對點聊天程序並解決上一篇中父進程退出,子進程不退出情況

p2psrv.c:

#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<signal.h>//解決父進程退出,子進程不退出

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#define ERR_EXIT(m) \
    do \
    { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)
void handler(int sig){
    printf("recv a sig=%d\n",sig);
    exit(EXIT_SUCCESS);//將子進程退出

}
void do_service(int conn)
{
    char recvbuf[1024];
        while(1){
                     memset(recvbuf,0,sizeof(recvbuf));//初始化recvbuf
                     int ret=read(conn,recvbuf,sizeof(recvbuf));//函數從打開的文件,設備中讀取數據,返回讀取的字節數。
                     if(ret==0)
             {
            printf("client_close\n");
            break;
             }
             else if(ret==-1)
             {
                ERR_EXIT("read");
             }
             fputs(recvbuf,stdout);
                     write(conn,recvbuf,ret);//buf中數據被複制到了TCP發送緩衝區
                }
}
int main(void)
{
    int listenfd;
    /*if((listenfd=socket(AF_INET,SOCK_STEAM,IPPOTO_TCP))<0) */
    if((listenfd=socket(AF_INET,SOCK_STREAM,0))<0)
        ERR_EXIT("socket");

    //IPV4地址結構
    struct sockaddr_in servaddr;
    memset(&servaddr,0,sizeof(servaddr));
    servaddr.sin_family=AF_INET;//地址家族
    servaddr.sin_port=htons(5188);//端口,主機轉網絡
    /*servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");*/
    /*inet_aton("127.0.0.1",&servaddr.sin_addr);*/
    servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
    int on=1;
    if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))<0)
        ERR_EXIT("setsockopt");

    if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
        ERR_EXIT("bind");


    if(listen(listenfd,SOMAXCONN)<0)
        ERR_EXIT("listen");

    struct sockaddr_in peeraddr;
    socklen_t peerlen =sizeof(peeraddr);//typedef int socklen_t
    int conn;//已連接套接字
    pid_t pid;

    if((conn=accept(listenfd,(struct sockaddr*)&peeraddr,&peerlen))<0)
        ERR_EXIT("accept");

    printf("ip=%s port=%d\n",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port));

    pid=fork();
    if(pid==-1)
        ERR_EXIT("fork");
    if(pid==0)//發送數據進程
    {
        signal(SIGUSR1,handler);
        char sendbuf[1024]={0};
        while(fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL)//從標準輸入獲取數據
        {
            write(conn,sendbuf,strlen(sendbuf));//發送到TCP緩衝區
            memset(sendbuf,0,sizeof(sendbuf));
        }

        exit(EXIT_SUCCESS);//將子進程退出,要不它會fork()
    }
    else//父進程用來獲取數據(接收數據進程)
    {
         char recvbuf[1024];
         while(1){
                     memset(recvbuf,0,sizeof(recvbuf));//初始化recvbuf
                     int ret=read(conn,recvbuf,sizeof(recvbuf));//函數從打開的文件,設備中讀取數據,返回讀取的字節數。
                     if(ret==0)
                     {
                        printf("peer_close\n");
                        break;//否則一直輸出“peer_close”
                     }
                     else if(ret==-1)
                     {
                        ERR_EXIT("read");
                     }
            fputs(recvbuf,stdout);

                    // write(conn,recvbuf,ret);//buf中數據被複制到了TCP發送緩衝區
                }
        printf("parent close\n");
        kill(pid,SIGUSR1);//父進程向子進程發送信號
        exit(EXIT_SUCCESS);
    } 

    return 0;
}

p2pcli:

#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<signal.h>

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#define ERR_EXIT(m) \
    do \
    { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)
void handler(int sig){
    printf("recv a sig=%d\n",sig);
    exit(EXIT_SUCCESS);
}
int main()
{
    int sock;
    /*if((listenfd=socket(AF_INET,SOCK_STEAM,IPPOTO_TCP))<0) */
    if((sock=socket(AF_INET,SOCK_STREAM,0))<0)
        ERR_EXIT("socket");

    //IPV4地址結構
    struct sockaddr_in servaddr;
    memset(&servaddr,0,sizeof(servaddr));
    servaddr.sin_family=AF_INET;//地址家族
    servaddr.sin_port=htons(5188);//端口,主機轉網絡
    servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
    /*inet_aton("127.0.0.1",&servaddr.sin_addr);*/


    if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
        ERR_EXIT("connect");

    pid_t pid;
    pid=fork();
    if(pid==-1)
        ERR_EXIT("fork");
    if(pid==0)
    {
        char recvbuf[1024];
        while(1){
            memset(recvbuf,0,sizeof(recvbuf));
            int ret=read(sock,recvbuf,sizeof(recvbuf));
            if(ret==-1)
                ERR_EXIT("read");
            else if(ret==0)
            {

                printf("peer close!\n");
                break;
            }
            fputs(recvbuf,stdout);
        }
        close(sock);    
        kill(getppid(),SIGUSR1);
    }
    else//發送數據
    {
        signal(SIGUSR1,handler);
        char sendbuf[1024]={0};
        while(fgets(sendbuf,sizeof(sendbuf),stdin) !=NULL){
                    write(sock,sendbuf,strlen(sendbuf));//發送
                        memset(sendbuf,0,sizeof(sendbuf));

             }
        close(sock);

    }
    return 0;


}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章