Linux网络编程学习笔记-简单点对点聊天程序--6

来源:互联网 发布:超融合软件下载 编辑:程序博客网 时间:2024/04/29 20:52

服务器端套接字分两种,一种是监听套接字,一个是已连接套接字。客户端只有已连接套接字
监听套接字主要用来接受三次握手数据,一旦三次握手完成了,那么就将其放到已连接队列中,accpet()就可以从中返回一个连接,返回的这个连接被称之为已连接套接字,是用来和客户端进行通信的,并不能接受连接,为主动套接字。
因此一个服务器端有3个客户机连接时,服务器端就有3个不同的已连接套接字,1个监听套接字。

下面是点对点聊天程序的实现:

/*服务器端程序*/#include <sys/types.h>#include <sys/socket.h>#include <stdio.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <string.h>#include <stdlib.h>#include <fcntl.h>#include <sys/shm.h>#define MYPORT  8887#define QUEUE   20#define BUFFER_SIZE 1024#define ERR_EXIT(m) \    do \    { \        perror(m); \        exit(EXIT_FAILURE); \    } while(0)int do_service(int conn){    char recvbuf[BUFFER_SIZE]={0};    memset(recvbuf,0,sizeof(recvbuf));    int length = recv(conn,recvbuf,sizeof(recvbuf),0);           if(length == 0){//客户端关闭的情况        //signal(SIGUSR1,handler);        printf("client close by accient\n");        return 0;    }     if(length < 0){ //如果失败        ERR_EXIT("recv");        return 0;    }    if(strcmp(recvbuf,"exit\n")==0)        return 0;    else{                 fputs(recvbuf,stdout);        return 1;    }      }int main(){   //定义客户端套接字    int sock_ser = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//最后一位可为0,自动    if(sock_ser <0)//如果失败        ERR_EXIT("socket");    //定义sockaddr_in    struct sockaddr_in addr_ser;    addr_ser.sin_family = AF_INET;    addr_ser.sin_port = htons(MYPORT);    addr_ser.sin_addr.s_addr = htonl(INADDR_ANY);    //开启地址重复利用    int on = 1;    int rel_set = setsockopt(sock_ser,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));    if(rel_set < 0)//如果失败        ERR_EXIT("reuseaddr");    //bind 绑定    int bd = bind(sock_ser,(struct sockaddr*)&addr_ser,sizeof(addr_ser));    if(bd < 0)//如果失败        ERR_EXIT("bind");    //listen 监听    int ln = listen(sock_ser,SOMAXCONN);//listen函数将套接字从主动套接字变成被动套接字;主动套接字主要用来发起连接,而被动套接字用来接受连接                                        //第二个参数规定能够并发连接的最大数目 =未完成连接数目+ 已完成连接数目:    if(ln < 0) //如果错误        ERR_EXIT("listen");    /*    开始定义客户端套接字      */    struct sockaddr_in addr_cli;    socklen_t len = sizeof(addr_cli);    //使用进程处理多并发    pid_t pid;    while(1){        //accept 接收        int conn = accept(sock_ser,(struct sockaddr*)&addr_cli,&len);        printf("ip=%s,port=%d\n",inet_ntoa(addr_cli.sin_addr),ntohs(addr_cli.sin_port));//新增打印通信ip和端口        if(conn < 0) //如果失败            ERR_EXIT("accept");        //创建父进程--发送数据        pid = fork();        if(pid == -1)            ERR_EXIT("fork");        if(pid == 0)//创建成功        {            char sendbuf[BUFFER_SIZE]={0};            while(fgets(sendbuf,sizeof(sendbuf),stdin) != NULL){                send(conn,sendbuf,sizeof(sendbuf),0);                memset(sendbuf,0,sizeof(sendbuf));            }            printf("child close \n");            exit(EXIT_SUCCESS);                        close(conn);        }        else        {            while(do_service(conn));                            printf("parent close\n");                         exit(EXIT_SUCCESS);            close(conn);        }    }    return 0;}
#include <sys/types.h>#include <sys/socket.h>#include <stdio.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <string.h>#include <stdlib.h>#include <fcntl.h>#include <sys/shm.h>#include <signal.h>#define MYPORT  8887#define BUFFER_SIZE 1024#define ERR_EXIT(m) \    do \    { \        perror(m); \        exit(EXIT_FAILURE); \    } while(0)void handler(int sig){    printf("recv a signal =%d\n",sig);    exit(EXIT_SUCCESS);    }int main(){   //定义客户端socket    int sock_cli = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);    if(sock_cli < 0 )//如果失败        ERR_EXIT("socket");   //定义sockaddr    struct sockaddr_in addr_cli;    addr_cli.sin_family = AF_INET;    addr_cli.sin_port = htons(MYPORT);    addr_cli.sin_addr.s_addr = inet_addr("127.0.0.1");    int conn = connect(sock_cli,(struct sockaddr*)&addr_cli,sizeof(addr_cli));    if(conn < 0)            ERR_EXIT("connect");    char recvbuf[BUFFER_SIZE]={0};    char sendbuf[BUFFER_SIZE]={0};      pid_t pid;    pid = fork();    if(pid == -1)        ERR_EXIT("fork");    if(pid == 0)//发送数据    {                while(1){            memset(recvbuf,0,sizeof(recvbuf));            int length = recv(sock_cli,recvbuf,sizeof(recvbuf),0);            if(length <0)                ERR_EXIT("recv");            else if(length == 0){                printf("peer close\n");                break;            }            fputs(recvbuf,stdout);                    }        close(conn);        kill(getppid(),SIGUSR1);    }    else    {                           while(fgets(sendbuf,sizeof(sendbuf),stdin)!=0){        send(sock_cli,sendbuf,sizeof(sendbuf),0);//发送               memset(sendbuf,0,sizeof(sendbuf));        }    }       close(conn);    return 0;   }
0 0