• 冯伟浩 2012.6.5 C/S-单播


    作者:2010级嵌入式  冯伟浩

    问题由来:  http://blog.chinaunix.net/uid-14735472-id-3216962.html

    ++++++++++++++++++++++++++++++++++
    [root@bogon ~]# gedit
    server.c
    /* server.c */
    #include
    #include
    #include
    #include
    #include "wrap.h"

    #define MAXLINE 80
    #define SERV_PORT 8000
    char buf[MAXLINE];
    int client[FD_SETSIZE];
    int i;
    int maxi;
    int doit(char *var, char *vbr);
    int main(int argc, char **argv)
    {
    int i, maxi, maxfd, listenfd, connfd, sockfd; int p=0,l=0,k=0,j;
    int nready, client[FD_SETSIZE];
    ssize_t n;
    pthread_t tidA;
    fd_set rset, allset;
    char buf[MAXLINE];
    memset(buf,0,MAXLINE);
    char str[INET_ADDRSTRLEN];
    socklen_t cliaddr_len;
    struct sockaddr_in cliaddr, servaddr;
    char dbuf[]="--";
    char cbuf[]="已登录!";
    char fbuf[]="收到的信息";
    char ebuf[]="用户已登录!请重新打开窗口输入!";
    char sookset1[MAXLINE][MAXLINE];
    memset(sookset1,0,MAXLINE*MAXLINE*sizeof(char));
    char buf2[MAXLINE][MAXLINE];
    char buf3[MAXLINE][MAXLINE];
    memset(buf3,0,MAXLINE*MAXLINE*sizeof(char));
    listenfd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);

    Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    Listen(listenfd, 20);

    maxfd = listenfd;
    maxi = -1;
    for (i = 0; i client[i] = -1;
    FD_ZERO(&allset);
    FD_SET(listenfd, &allset);
    for (;;) {
    rset = allset;
    nready = select(maxfd + 1, &rset, NULL, NULL, NULL);//剔除
    if (nready < 0)
    perr_exit("select error");

    if (FD_ISSET(listenfd, &rset)) {
    cliaddr_len = sizeof(cliaddr);
    connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);

    printf("received from %s at PORT %d ", inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), ntohs(cliaddr.sin_port));

    for (i = 0; i < FD_SETSIZE; i++)
    if (client[i] < 0) {
    printf("i=%d ",i);
    //打印I的值,i从0开始加
    client[i] = connfd; /* save descriptor */
    sookset1[i][0]=connfd;
    //定义二维数组只用下标为[i][0]的位置来存放文件描述符!每打开一个客户端链接i的值自动的加加。。i从0开始加..存放客户端文件描述符的分别是[0][0],[1][0],[2][0]
    printf("sookset1[p][0]=%s ",sookset1[p]);
    //控制流程将sookset1[p]的值打印出来。
    break;
    }

    if (i == FD_SETSIZE) {
    fputs("too many clients ", stderr);
    exit(1);
    }

    FD_SET(connfd, &allset);
    if (connfd > maxfd)
    maxfd = connfd;
    if (i > maxi)
    maxi = i;
    if (--nready == 0)
    continue;
    }

    for (i = 0; i <= maxi; i++) {
    if ( client[i] < 0)
    {continue;}else
    {
    sockfd = client[i];
    }
    lable1: if (FD_ISSET(sockfd, &rset)) {
    memset(buf,0,MAXLINE);
    if ((n = Read(sockfd, buf, MAXLINE)) == 0) {
    Close(sockfd);
    FD_CLR(sockfd, &allset);
    client[i] = -1;
    } else {
    printf("maxi=%d ",maxi);
    for(j = 0; j <= maxi; j++)
    {
    printf("buf3[1]=%s ",buf3[j]);
    printf("buf=%s ",buf);
    if(strcmp(buf3[j],buf)==0)
    {
    for (i = 0; i <= maxi; i++)
    {
    Write(client[i], ebuf, n);
    } goto lable1;
    }
    }
    if(strstr(buf,dbuf)==NULL)
    //用来判断客户端输入的是用户名还是信息!查找buf中是否含有dbuf,我觉的这个用的不好,但是一时也没想开咋该。
    {
    printf("执行了一次! "); //成功执行这下面的代码,控制流程
    printf("i=%d ",i); //打印活动的文件描述符的下标!从0开始
    strcat(sookset1[i],buf);//将文件描述符和用户输入的用户名进行链接,分别放入sookset1中
    printf("sookset1[i]=%s ",sookset1[i]); //打印链接后的sookset1[i]
    strcat(buf2[i],buf);
    strcat(buf3[i],buf);
    printf("buf2[i]=%s ",buf2[i]);
    strcat(buf2[i],dbuf);//必须是英文情况下的--
    strcat(buf2[i],cbuf);//执行后即为谁--已登录
    //strcat(buf2[i],buf);
    for (i = 0; i <= maxi; i++)
    for (j = 0; j<= maxi; j++)
    {
    Write(client[i], buf2[j], n);//每次客户运行将已登录的信息循环发给每个用户
    }//将客户端输入的信息循环写入
    }else{ //如果输入的是信息执行下列代码
    for(j=0;j<=maxi;j++)
    {
    printf("打印@ ");
    printf("buf=%s ",buf);//将读入的客户端信息放入buf中并打印
    printf("sookset1[j]=%s ",sookset1[j]); //将此时sookset1[j]的信息打印出来
    if(doit(sookset1[j],buf)==1)//判断sookset1[j]的信息何buf的信息是否相等
    {
    printf("sookset1[j][0]=%c ",sookset1[j][0]); //打印此时的文件描述符
    j=(int)sookset1[j][0];//将sookset1[j][0]中的文件描述符转化为整形
    printf("%d ",j);
    Write(j, buf, n);//将信息写入客户端
    }
    }
    }

    }
    if (--nready == 0)
    break;
    }
    }
    }
    }

    int doit(char *var, char *vbr) //函数用来比较sookset1[j]和buf是否相等,此时sookset1[j]相当于一维字符串数组
    {
    int k;
    for(k=0;k<10;k++)
    {
    if(var[k+1]=='-' || vbr[k]=='-')
    //for循环下标从头开始比较,因为sookset1[j]中sookset1[j][0]为文件描述符所以从k+1处开始比较
    {
    break;
    }else{
    if(var[k+1]==vbr[k])
    {
    continue;
    }else{
    if(var[k+1]!=vbr[k])
    {
    return 0;
    }
    }
    }
    }
    return 1;

    }

    ++++++++++++++++++++++++++++++++++++
    [root@bogon ~]# gedit client.c
    /* client.c */
    #include
    #include
    #include
    #include
    #include "wrap.h"

    #define MAXLINE 80
    #define SERV_PORT 8000
    void *doit(void *arg);
    char buf[MAXLINE];
    int main(int argc, char *argv[])
    {
    struct sockaddr_in servaddr;
    char buf[MAXLINE];
    memset(buf,0,MAXLINE);
    int sockfd, n;
    pthread_t tidA;
    if (argc != 2) {
    fprintf(stderr,"请输入要发送的信息 ");
    exit(1);
    }
    strcpy(buf,argv[1]);

    sockfd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
    servaddr.sin_port = htons(SERV_PORT);
    printf("请输入用户名形如xxx--xxx ");
    printf("请勿输入重复的用户名!发送信息时请输入要发送的用户名+您要输入的信息! ");
    printf("如果输入重复的用户名!请重新打开窗口! ");

    printf("请输入esc退出程序! ");
    Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    write(sockfd,buf,MAXLINE);
    while (1) {
    pid_t pid;
    char *message;
    int n;
    pid = fork();
    if (pid < 0) {
    perror("fork failed");
    exit(1);
    }
    if (pid == 0) {
    memset(buf,0,MAXLINE);
    n = Read(sockfd, buf, MAXLINE);
    if (n == 0)
    { printf("the servre has closed. ");break; }
    else
    //Write(STDOUT_FILENO, buf, n);
    printf("%s ",buf);
    printf("------------------------ ");
    } else {
    fgets(buf, MAXLINE, stdin);
    if(memcmp(buf,"esc",3)==0)
    {
    exit(1);
    }
    Write(sockfd, buf, strlen(buf));
    }

    }

    Close(sockfd);
    return 0;
    }

    ++++++++++++++++++++++++++++++++++++++++
    [root@bogon ~]# gedit wrap.h

    #include
    #include
    #include

    void perr_exit(const char *s)
    {
            perror(s);
            exit(1);
    }

    int Accept(int fd, struct sockaddr *sa, socklen_t * salenptr)
    {
            int n;

          again:
            if ((n = accept(fd, sa, salenptr)) < 0) {
                    if ((errno == ECONNABORTED) || (errno == EINTR))
                            goto again;
                    else
                            perr_exit("accept error");
            }
            return n;
    }

    void Bind(int fd, const struct sockaddr *sa, socklen_t salen)
    {
            if (bind(fd, sa, salen) < 0)
                    perr_exit("bind error");
    }

    void Connect(int fd, const struct sockaddr *sa, socklen_t salen)
    {
            if (connect(fd, sa, salen) < 0)
                    perr_exit("connect error");
    }

    void Listen(int fd, int backlog)
    {
            if (listen(fd, backlog) < 0)
                    perr_exit("listen error");
    }

    int Socket(int family, int type, int protocol)
    {
            int n;

            if ((n = socket(family, type, protocol)) < 0)
                    perr_exit("socket error");
            return n;
    }

    ssize_t Read(int fd, void *ptr, size_t nbytes)
    {
            ssize_t n;

          again:
            if ((n = read(fd, ptr, nbytes)) == -1) {
                    if (errno == EINTR)
                            goto again;
                    else
                            return -1;
            }
            return n;
    }

    ssize_t Write(int fd, const void *ptr, size_t nbytes)
    {
            ssize_t n;

          again:
            if ((n = write(fd, ptr, nbytes)) == -1) {
                    if (errno == EINTR)
                            goto again;
                    else
                            return -1;
            }
            return n;
    }

    void Close(int fd)
    {
            if (close(fd) == -1)
                    perr_exit("close error");
    }

    ssize_t Readn(int fd, void *vptr, size_t n)
    {
            size_t nleft;
            ssize_t nread;
            char *ptr;

            ptr = vptr;
            nleft = n;
            while (nleft > 0) {
                    if ((nread = read(fd, ptr, nleft)) < 0) {
                            if (errno == EINTR)
                                    nread = 0;
                            else
                                    return -1;
                    } else if (nread == 0)
                            break;

                    nleft -= nread;
                    ptr += nread;
            }
            return n - nleft;
    }

    ssize_t Writen(int fd, const void *vptr, size_t n)
    {
            size_t nleft;
            ssize_t nwritten;
            const char *ptr;

            ptr = vptr;
            nleft = n;
            while (nleft > 0) {
                    if ((nwritten = write(fd, ptr, nleft)) <= 0) {
                            if (nwritten < 0 && errno == EINTR)
                                    nwritten = 0;
                            else
                                    return -1;
                    }

                    nleft -= nwritten;
                    ptr += nwritten;
            }
            return n;
    }

    static ssize_t my_read(int fd, char *ptr)
    {
            static int read_cnt;
            static char *read_ptr;
            static char read_buf[100];

            if (read_cnt <= 0) {
                  again:
                    if ((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
                            if (errno == EINTR)
                                    goto again;
                            return -1;
                    } else if (read_cnt == 0)
                            return 0;
                    read_ptr = read_buf;
            }
            read_cnt--;
            *ptr = *read_ptr++;
            return 1;
    }

    ssize_t Readline(int fd, void *vptr, size_t maxlen)
    {
            ssize_t n, rc;
            char c, *ptr;

            ptr = vptr;
            for (n = 1; n < maxlen; n++) {
                    if ((rc = my_read(fd, &c)) == 1) {
                            *ptr++ = c;
                            if (c == ' ')
                                    break;
                    } else if (rc == 0) {
                            *ptr = 0;
                            return n - 1;
                    } else
                            return -1;
            }
            *ptr = 0;
            return n;
    }

    +++++++++++++++++++++++++++++
    执行过程:
    客户端一:[root@bogon  select]# ./clie3 asd
    请输入用户名形如xxx--xxx
    请勿输入重复的用户名!发送信息时请输入要发送的用户名+您要输入的信息!
    如果输入重复的用户名!请重新打开窗口!
    请输入esc退出程序!
    asd--已登录!
    ------------------------
    asd--已登录!
    ------------------------
    qwe--已登录!
    ------------------------
    asd--asdfsdfsdf    //qwe给asd的信息

    ------------------------
    qwe--asdfsdfdsf   //发给qwe的信息
    asd--已登录!
    ------------------------
    qwe--已登录!
    ------------------------
    zxc--已登录!
    ------------------------
    asd--sadfdsf   //zxc给asd的信息

    ------------------------
    zxc--asdfdsf    //回给zxc的信息
    用户已登录!请重新打开窗口输入!   //  //将第四个重复的用户也广播出去!
    客户端二:
    [root@bogon  select]# ./clie3 qwe
    请输入用户名形如xxx--xxx
    请勿输入重复的用户名!发送信息时请输入要发送的用户名+您要输入的信息!
    如果输入重复的用户名!请重新打开窗口!
    请输入esc退出程序!
    asd--已登录!
    ------------------------
    qwe--已登录!
    ------------------------
    asd--asdfsdfsdf     发给asd的信息
    qwe--asdfsdfdsf    asd 发给qwe的信息

    ------------------------
    asd--已登录!
    ------------------------
    qwe--已登录!
    ------------------------
    zxc--已登录!
    ------------------------
    用户已登录!请重新打开窗口输入!           //将第四个重复的用户也广播出去!
    ------------------------
    客户端三:
    [root@bogon  select]# ./clie3 zxc
    请输入用户名形如xxx--xxx
    请勿输入重复的用户名!发送信息时请输入要发送的用户名+您要输入的信息!
    如果输入重复的用户名!请重新打开窗口!
    请输入esc退出程序!
    asd--已登录!
    ------------------------
    qwe--已登录!
    ------------------------
    zxc--已登录!
    ------------------------
    asd--sadfdsf    
    zxc--asdfdsf

    ------------------------
    用户已登录!请重新打开窗口输入!    //  //将第四个重复的用户也广播出去!
    ------------------------
    [root@bogon  select]# ./clie3 asd              //登录用户名重复!
    请输入用户名形如xxx--xxx
    请勿输入重复的用户名!发送信息时请输入要发送的用户名+您要输入的信息!
    如果输入重复的用户名!请重新打开窗口!
    请输入esc退出程序!
    用户已登录!请重新打开窗口输入!
    ------------------------




    <script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
    阅读(614) | 评论(0) | 转发(2) |
    给主人留下些什么吧!~~
    评论热议
  • 相关阅读:
    重启停止的作业 bg和fg
    shell nohup 让脚本一直以后台模式运行到结束
    shell jobs查看作业
    shell 移除信号捕获
    shell 多进程运行程序
    shell 脚本后台运行
    python3 生产者消费者
    python3 生产者消费者(守护线程)
    python3 进程线程协程 并发查找列表
    python3 线程间通信
  • 原文地址:https://www.cnblogs.com/ztguang/p/12648081.html
Copyright © 2020-2023  润新知