zoukankan      html  css  js  c++  java
  • Linux下p2p的聊天功能实现

    Linux下p2p的聊天功能实现细节

    Do one thing at a time, and do well.

    今天闲着没事,写一个P2P的点对点的聊天功能的小程序,我觉得对网络编程初学者的学习很有用的。二话不说,我先贴代码吧。有几个地方需要考虑清楚。我会在代码的后面写出来。代码的下载文章的末尾。

    server.c

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <stdlib.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <string.h>
    #include <signal.h>
    
    #define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); } while(0) void do_something(int conn) { char recvbuf[1024]; for(;;) { memset(recvbuf,0,sizeof(recvbuf)); int ret = read(conn,recvbuf,sizeof(recvbuf)); if(ret == 0) { printf("client closed! "); break; } else if(ret == -1) { ERR_EXIT("read"); } fputs(recvbuf,stdout); write(conn,recvbuf,ret); } } void handler(int sig) { printf("recv a sig = %d ",sig); exit(EXIT_SUCCESS); } int main() { int listenfd; if((listenfd = socket(AF_INET,SOCK_STREAM,0)) < 0) ERR_EXIT("socket"); int on = 1; int ret = setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on) ); struct sockaddr_in servaddr; memset(&servaddr,0,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(10001); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 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 socklen = sizeof(peeraddr); int conn; pid_t pid; if((conn = accept(listenfd,(struct sockaddr*)&peeraddr,&socklen)) < 0)// 获得到是主动套接字 ERR_EXIT("accept"); printf("ip:%s port:%d ",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port)); pid = fork(); char sendbuf[1024] = {0}; if(pid == -1) ERR_EXIT("pid"); if(pid == 0) { signal(SIGUSR1,handler); while(fgets(sendbuf,sizeof(sendbuf),stdin) != NULL) { write(conn,sendbuf,strlen(sendbuf)); memset(sendbuf,0,sizeof(sendbuf)); } printf("child closed "); exit(EXIT_SUCCESS); } else { char recvbuf[1024]; while(1) { memset(recvbuf,0,sizeof(recvbuf)); int ret = read(conn,recvbuf,sizeof(recvbuf)); if(ret == -1) ERR_EXIT("read"); else if(ret == 0) { printf("peer close "); break; } fputs(recvbuf,stdout); } printf("kill parent! "); kill(pid,SIGUSR1); exit(EXIT_SUCCESS); //do_something(conn); } close(conn); close(listenfd); exit(0); }
    #include <stdio.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <arpa/inet.h>
    #include <signal.h>
    
    #define ERR_EXIT(m) 
         do 
         {  
               perror(m); 
               exit(EXIT_FAILURE); 
         } while(0)
    
    void handler(int sig)
    {
        printf("recv a sig = %d
    ",sig);
        exit(EXIT_SUCCESS);
    }
    
    
    int main(int argc,char *argv[])
    {
        int sockfd;
        if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
          ERR_EXIT("socket");
        struct sockaddr_in servaddr;
        memset(&servaddr,0,sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(10001);
        servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    
        if(connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0)
          ERR_EXIT("connect");
    
        char sendbuf[1024] = {0};
        char recvbuf[1024] = {0};
        pid_t pid;
        pid = fork();
        if(pid == -1)
            ERR_EXIT("fork");
        if(pid == 0)
        {
            while(1)
            {
                memset(recvbuf,0,sizeof(recvbuf));
                int ret = read(sockfd,recvbuf,sizeof(recvbuf));
                if(ret == -1)
                    ERR_EXIT("read");
                else if (ret == 0)
                {
                    printf("peer closed
    ");
                    break;
                }
                fputs(recvbuf,stdout);
            }
    
            printf("child close
    ");
            kill(pid,SIGUSR1);
            exit(EXIT_SUCCESS);
        }
        else
        {        
            signal(SIGUSR1,handler);
            while(fgets(sendbuf,sizeof(sendbuf),stdin) != NULL)
            {
                write (sockfd,sendbuf,strlen(sendbuf));  
                memset(sendbuf,0,sizeof(sendbuf));
            }
            printf("parent close!
    ");
        }
        close(sockfd);
        exit(0);
    }

    实现的功能很简单,但是需要注意的几个细节:

    1、C和S连接以后,当S关闭后,C仍然没有关闭,我用到了信号的功能。

         实现的方法:当父进程关闭的时候,子进程也关闭,当子进程关闭的时候,把父进程也关闭了。

    2、一个线程用来监听,一个线程用来等待输入。那么,这是一个多线程的小程序。

      创建一个子进程。C端,子进程进程监听,父进程等待输入。S端相反。

    3、信号量的问题:

      SIGUSR1:用户自定义信号量,函数handler用来杀死进程,实现退出。

    程序的测试:

    总结:总的来说,这个还是很简单的,也就是几个函数是否灵活应用。注意,read函数如果没有读到,就会进入阻塞,如果收到一个0,代表对方关闭了程序,则退出程序。

    代码下载:GitHub

    声明:水平有限,如果有什么地方写错了或者理解有误,希望广大网友指正。

  • 相关阅读:
    Treap 树堆 容易实现的平衡树
    (转)Maven实战(二)构建简单Maven项目
    (转)Maven实战(一)安装与配置
    根据请求头跳转判断Android&iOS
    (转)苹果消息推送服务器 php 证书生成
    (转)How to renew your Apple Push Notification Push SSL Certificate
    (转)How to build an Apple Push Notification provider server (tutorial)
    (转)pem, cer, p12 and the pains of iOS Push Notifications encryption
    (转)Apple Push Notification Services in iOS 6 Tutorial: Part 2/2
    (转)Apple Push Notification Services in iOS 6 Tutorial: Part 1/2
  • 原文地址:https://www.cnblogs.com/yusenwu/p/4613794.html
Copyright © 2011-2022 走看看