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;


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