zoukankan      html  css  js  c++  java
  • 错误的尝试:回射程序改进2

    在回射程序的基础上,设计一个类似于群聊的应用

    与改进1相比增加的设计:

    1.将每个客户端发出的消息增加一个字符串,用于表示发送者的身份

    2.服务端将收到的每个客户端消息转发给其他已连接的客户端套接字

    改进1:https://www.cnblogs.com/lnlin/p/9568279.html

    改进的思考过程:

    1.消息头的增加:

    增加一个客户端mian函数参数,用于表示用户名。

    将每个客户端用户名添加到客户端发送的消息头部来表名某个消息发送者的身份,添加方式:

    a.在客户端在标准输入输入消息后,客户端自动将此客户端用户用户名字符串添加到消息头部,再将

    添加了用户名的消息发送给服务端

    b.在客户端与服务端建立连接后,将客户端用户名发送给服务端,服务端保存此用户名,并在转发客

    户端消息时,将相应用户名添加到相应消息数据中

    下面的实现选用 a 方法,原因是我考虑到这么做虽然增加了客户端发送给服务端的消息长度,但减少

    了客户端所需要的操作。

    客户端main函数:

      1 #include "net.h"
      2 
      3 int main(int argc, char **argv)
      4 {
      5     int sockfd;
      6 
      7     if (argc != 3)
      8     {
      9         printf("Error arg!
    ");
     10         exit(1);
     11     }
     12 
     13     printf("%s
    ", argv[2]);
     14 
     15     sockfd = tcp_connect(argv[1], SERV_PORT);
     16     printf("Success init, the connected socket is %d
    ", sockfd);
     17     cli_io(sockfd, argv[2]);
     18 
     19     return 0;
     20 }

    将一个字符串添加到另一个字符串头部:

     35 // 将一个字符串放到另一个字符串的头部,构造将用户名加到客户发送的消息中
     36 // 不提供对字符串空间大小的检查
     37 char *addStrHead(char *head, char *row)
     38 {
     39     int headLen, rowLen, i;
     40     headLen = strlen(head);
     41     rowLen = strlen(row);
     42 
     43     for (i = headLen + rowLen; i >= 0; i--)
     44     {
     45         if (i > headLen)
     46         {
     47             row[i] = row[i - headLen - 1];
     48         }
     49         else if (i == headLen)
     50         {
     51             row[i] = ':';
     52         }
     53         else
     54         {
     55             row[i] = head[i];
     56         }
     57     }
     58 
     59     row[headLen + rowLen + 1] = '';
     60 
     61     return row;
     62 }

    与改进1相比变化的cli_io函数:

     64 // 回射程序客户端对套接字的读写
     65 void cli_io(int sockfd, char *mark)
     66 {
     67     int n;
     68     char sendline[MAXLINE], recvline[MAXLINE];
     69 
     70     while (fgets(sendline, MAXLINE, stdin) != NULL)
     71     {
     72         // 将用户名添加到消息头部
     73         addStrHead(mark, sendline);
     74         
     75         if (write(sockfd, sendline, strlen(sendline)) < 0)
     76         {   
     77             printf("Error write!
    ");
     78             exit(1);
     79         }
     80         
     81         if ( (n = read(sockfd, recvline, MAXLINE)) > 0 )
     82         {   
     83             recvline[n] = '';
     84             fputs(recvline, stdout);
     85         }
     86     }
     87     
     88     return;
     89 }

    服务端改进:

    将从客户端收到的消息转发自其他已连接套接字

    错误的尝试:在使用fork创建子进程的方式来处理每个自连接的基础上,在服务端添加一个结构用于保

    存所有连接过的套接字与相应套接字的存活状态,每个子进程在收到此消息后通过此套接字列表转发消

    息。

    错误原因思考:如果父进程先创建子进程,后父进程生成socket,这些socket和子进程无关

    服务端代码:

      1 #include "net.h"
      2 
      3 
      4 int main(int argc, char **argv)
      5 {
      6     int listenfd, connfd, n;
      7     struct sockaddr_in cliaddr;
      8     pid_t childpid;
      9     socklen_t clilen;
     10 
     11     // 为所有与服务器建立连接的套接字创建一个存储数组
     12     struct sockConn socklist[MAXSOCKET];
     13     int cntSockfd = 0;
     14     listenfd = tcp_listen(SERV_PORT);
     15     for ( ; ; )
     16     {
     17         clilen = sizeof(cliaddr);
     18 
     19         if ( (connfd = accept(listenfd, (SA *) &cliaddr, &clilen)) < 0 )
     20         {
     21             printf("Error accept!
    ");
     22             exit(0);
     23         }
     24 
     25         printf("accept: %d
    ", connfd);
     26 
     27         addSockfd(connfd, socklist, &cntSockfd);
     28 
     29         if ( (childpid = fork()) == 0 )
     30         {
     31             if (close(listenfd) < 0)
     32             {
     33                 printf("Error close!
    ");
     34                 exit(1);
     35             }
     36 
     37             serv_io(connfd, socklist, &cntSockfd);
     38             exit(0);
     39         }
     40     }
     41 }

    所用函数:

     35 // 将从某一客户端接收的数据群发到所有已连接的客户(套接字)
     36 void send2All(char *message, int itself, struct sockConn *socklist, int *cntSockfd)
     37 {
     38     int i;
     39 
     40     for (i = 0; i < *cntSockfd; i++)
     41     {
     42         if (socklist[i].used && socklist[i].sockfd != itself)
     43         {
     44             if (write(socklist[i].sockfd, message, strlen(message)) < 0)
     45             {
     46                 printf("Error write!
    ");
     47                 exit(1);
     48             }
     49         }
     50     }
     51 
     52     return;
     53 }
     54 
     55 // 服务端io
     56 void serv_io(int connfd, struct sockConn *socklist, int *cntSockfd)
     57 {
     58     char buff[MAXLINE];
     59     int n;
     60 
     61     while ( (n = read(connfd, buff, MAXLINE)) > 0 )
     62     {
     63         buff[n] = '';
     64         fputs(buff, stdout);
     65 
     66         if (write(connfd, buff, strlen(buff)) < 0)
     67         {
     68             printf("Error write!
    ");
     69             exit(1);
     70         }
     71 
     72         //send2All(buff, connfd, socklist, cntSockfd);
     73     }
     74 
     75     return;
     76 }
     77 
     78 // 在accept后将已连接套接字加入socklist,并将已连接过的套接字数加一
     79 void addSockfd(int sockfd, struct sockConn *socklist, int *cntSockfd)
     80 {
     81     socklist[*cntSockfd].sockfd = sockfd;
     82     socklist[*cntSockfd].used = 1;
     83     *cntSockfd++;
     84 
     85     return;
     86 }
     87 
  • 相关阅读:
    PHP开发学习门户改版效果图投票
    怎样用js得到当前页面的url信息方法(JS获取当前网址信息)
    java 获取当期时间之前几小时的时间
    超人学院Hadoop大数据技术资源分享
    plsql导入一个目录下全部excel
    UML简单介绍
    Mod in math
    父母之爱子,则为之计深远是什么意思?_百度知道
    2014创客118新年大爬梯_活动行-国内最好的活动报名及售票平台!
    北京创客空间 BEIJING MAXPACE的小站
  • 原文地址:https://www.cnblogs.com/lnlin/p/9593771.html
Copyright © 2011-2022 走看看