linux下TCP通信简单实例

基于TCP(面向连接)的socket编程,分为服务器端和客户端

服务器端的流程如下:

(1)创建套接字(socket)

(2)将套接字绑定到一个本地地址和端口上(bind)

(3)将套接字设为监听模式,准备接收客户端请求(listen)

(4)等待客户请求到来;当请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept)

(5)用返回的套接字和客户端进行通信(send/recv)

(6)返回,等待另一个客户请求。

(7)关闭套接字。

客户端的流程如下:

(1)创建套接字(socket)

(2)向服务器发出连接请求(connect)

(3)和服务器端进行通信(send/recv)

(4)关闭套接字


下面通过一个具体例子讲解一下具体的过程和相关的函数,环境是suse linux。

    #include   
    #include   
    #include   
    #include   
    #include   
    #include   
    #include   
    //#include   
    #include   
    //#include   
    #include   
      
    #include   
      
    /** 
      关于 sockaddr  sockaddr_in  socketaddr_un说明 
      http://maomaozaoyue.blog.sohu.com/197538359.html 
      */  
      
    #define PORT    11910   //定义通信端口  
    #define BACKLOG 5       //定义侦听队列长度  
    #define buflen  1024  
      
    void process_conn_server(int s);  
    void sig_pipe(int signo);  
      
    int ss,sc;  //ss为服务器socket描述符,sc为某一客户端通信socket描述符  
      
    int main(int argc,char *argv[])  
    {  
      
        struct sockaddr_in server_addr; //存储服务器端socket地址结构  
        struct sockaddr_in client_addr; //存储客户端 socket地址结构  
      
        int err;    //返回值  
        pid_t pid;  //分叉进行的ID  
      
        /*****************socket()***************/  
        ss = socket(AF_INET,SOCK_STREAM,0); //建立一个序列化的,可靠的,双向连接的的字节流  
        if(ss<0)  
        {  
            printf("server : server socket create error\n");  
            return -1;  
        }  
        //注册信号  
        sighandler_t ret;  
        ret = signal(SIGTSTP,sig_pipe);  
        if(SIG_ERR == ret)  
        {  
            printf("信号挂接失败\n");  
            return -1;  
        }  
        else  
            printf("信号挂接成功\n");  
      
      
        /******************bind()****************/  
        //初始化地址结构  
        memset(&server_addr,0,sizeof(server_addr));  
        server_addr.sin_family = AF_INET;           //协议族  
        server_addr.sin_addr.s_addr = htonl(INADDR_ANY);   //本地地址  
        server_addr.sin_port = htons(PORT);  
      
        err = bind(ss,(struct sockaddr *)&server_addr,sizeof(sockaddr));  
        if(err<0)  
        {  
            printf("server : bind error\n");  
            return -1;  
        }  
      
        /*****************listen()***************/  
        err = listen(ss,BACKLOG);   //设置监听的队列大小  
        if(err < 0)  
        {  
            printf("server : listen error\n");  
            return -1;  
        }  
      
        /****************accept()***************/  
        /** 
        为类方便处理,我们使用两个进程分别管理两个处理: 
        1,服务器监听新的连接请求;2,以建立连接的C/S实现通信 
        这两个任务分别放在两个进程中处理,为了防止失误操作 
        在一个进程中关闭 侦听套接字描述符 另一进程中关闭 
        客户端连接套接字描述符。注只有当所有套接字全都关闭时 
        当前连接才能关闭,fork调用的时候父进程与子进程有相同的 
        套接字,总共两套,两套都关闭掉才能关闭这个套接字 
        */  
      
        for(;;)  
        {  
            socklen_t addrlen = sizeof(client_addr);  
            //accept返回客户端套接字描述符  
            sc = accept(ss,(struct sockaddr *)&client_addr,&addrlen);  //注,此处为了获取返回值使用 指针做参数  
            if(sc < 0)  //出错  
            {  
                continue;   //结束此次循环  
            }  
            else  
            {  
                printf("server : connected\n");  
            }  
      
            //创建一个子线程,用于与客户端通信  
            pid = fork();  
            //fork 调用说明:子进程返回 0 ;父进程返回子进程 ID  
            if(pid == 0)        //子进程,与客户端通信  
            {  
                close(ss);  
                process_conn_server(sc);  
            }  
            else  
            {  
                close(sc);  
            }  
        }  
    }  
      
    /** 
      服务器对客户端连接处理过程;先读取从客户端发送来的数据, 
      然后将接收到的数据的字节的个数发送到客户端 
      */  
      
    //通过套接字 s 与客户端进行通信  
    void process_conn_server(int s)  
    {  
        ssize_t size = 0;  
        char buffer[buflen];  //定义数据缓冲区  
        for(;;)  
        {  
            //等待读  
            for(size = 0;size == 0 ;size = read(s,buffer,buflen));  
            //输出从客户端接收到的数据  
            printf("%s",buffer);  
      
            //结束处理  
            if(strcmp(buffer,"quit") == 0)  
            {  
                close(s);   //成功返回0,失败返回-1  
                return ;  
            }  
            sprintf(buffer,"%d bytes altogether\n",size);  
            write(s,buffer,strlen(buffer)+1);  
        }  
    }  
    void sig_pipe(int signo)  
    {  
        printf("catch a signal\n");  
        if(signo == SIGTSTP)  
        {  
            printf("接收到 SIGTSTP 信号\n");  
            int ret1 = close(ss);  
            int ret2 = close(sc);  
            int ret = ret1>ret2?ret1:ret2;  
            if(ret == 0)  
                printf("成功 : 关闭套接字\n");  
            else if(ret ==-1 )  
                printf("失败 : 未关闭套接字\n");  
      
            exit(1);  
        }  
    }  


客户端代码:

    #include   
    #include   
    #include   
    #include   
    #include   
    //#include   
    #include   
    #include   
    #include   
    #include   
      
    #include  //添加信号处理  防止向已断开的连接通信  
      
    /** 
      信号处理顺序说明:在Linux操作系统中某些状况发生时,系统会向相关进程发送信号, 
      信号处理方式是:1,系统首先调用用户在进程中注册的函数,2,然后调用系统的默认 
      响应方式,此处我们可以注册自己的信号处理函数,在连接断开时执行 
      */  
      
      
    #define PORT    11910  
    #define Buflen  1024  
      
    void process_conn_client(int s);  
    void sig_pipe(int signo);    //用户注册的信号函数,接收的是信号值  
      
    int s;  //全局变量 , 存储套接字描述符  
      
    int main(int argc,char *argv[])  
    {  
      
        sockaddr_in server_addr;  
        int err;  
        sighandler_t ret;  
        char server_ip[50] = "";  
        int port = 0;
        strcpy(server_ip, argv[1]);
        port = atoi(argv[2]);

        /********************socket()*********************/  
        s= socket(AF_INET,SOCK_STREAM,0);  
        if(s<0)  
        {  
            printf("client : create socket error\n");  
            return 1;  
        }  
        printf("client : socket fd = %d\n", s); 
        //信号处理函数  SIGINT 是当用户按一个 Ctrl-C 建时发送的信号  
        ret = signal(SIGTSTP,sig_pipe);  
        if(SIG_ERR == ret)  
        {  
            printf("信号挂接失败\n");  
            return -1;  
        }  
        else  
            printf("信号挂接成功\n") ;  
      
      
        /*******************connect()*********************/  
        //设置服务器地址结构,准备连接到服务器  
        memset(&server_addr,0,sizeof(server_addr));  
        server_addr.sin_family = AF_INET;  
        server_addr.sin_port = htons(PORT);  
        server_addr.sin_addr.s_addr = htonl(INADDR_ANY);  
      
        /*将用户数入对额字符串类型的IP格式转化为整型数据*/  
        //inet_pton(AF_INET,argv[1],&server_addr.sin_addr.s_addr);  
        printf("please input server ip address : \n");  
        read(0,server_ip,50);  
        //err = inet_pton(AF_INET,server_ip,&server_addr.sin_addr.s_addr);  
        server_addr.sin_addr.s_addr = inet_addr(server_ip);  
      
        err = connect(s,(struct sockaddr *)&server_addr,sizeof(sockaddr));  
        if(err == 0)  
        {  
            printf("client : connect to server\n");  
        }  
        else  
        {  
            printf("client : connect error\n");  
            return -1;  
        }  
        //与服务器端进行通信  
        process_conn_client(s);  
        close(s);  
      
    }  
    void process_conn_client(int s)  
    {  
      
        ssize_t size = 0;  
        char buffer[Buflen];  
      
        for(;;)  
        {  
            memset(buffer,'\0',Buflen);  
            /*从标准输入中读取数据放到缓冲区buffer中*/  
            size = read(0,buffer,Buflen);   // 0,被默认的分配到标准输入  1,标准输出  2,error  
            if(size >  0)  
            {  
                //当向服务器发送 “quit” 命令时,服务器首先断开连接  
                write(s,buffer,strlen(buffer)+1);   //向服务器端写  
      
                //等待读取到数据  
                for(size = 0 ; size == 0 ; size = read(s,buffer,Buflen) );  
      
                write(1,buffer,strlen(buffer)+1);   //向标准输出写  
            }  
        }  
    }  
      
    void sig_pipe(int signo)    //传入套接字描述符  
    {  
        printf("Catch a signal\n");  
        if(signo == SIGTSTP)  
        {  
      
            printf("接收到 SIGTSTP 信号\n");  
            int ret = close(s);  
            if(ret == 0)  
                printf("成功 : 关闭套接字\n");  
            else if(ret ==-1 )  
                printf("失败 : 未关闭套接字\n");  
            exit(1);  
        }  
    }  

你可能感兴趣的:(linux)