• 用c写一个小的聊天室程序


    1.聊天室程序——客户端

         客户端我也用了select进行I/O复用,同时监控是否有来自socket的消息和标准输入,近似可以完成对键盘的中断使用。

    其中select的监控里,STDOUTSTDIN是已有规定的值了。

    Socket_setup函数负责进行对socket进行初始化完成connect 的过程,然后在主函数里无限循环检查sockfdSTDIN的缓冲区是否有新的消息

    客户端程序较简单:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <string.h>
     4 #include <stdbool.h>
     5 #include <unistd.h>
     6 #include <sys/socket.h>
     7 #include <arpa/inet.h>
     8 
     9 #define BUF_SIZE 256
    10 #define STDIN 0
    11 #define STDOUT 1
    12 #define INVALID -1
    13 
    14 int
    15 socket_setup(const char *serv_ip, int serv_port)
    16 {
    17     int rtn,sockfd;
    18     struct sockaddr_in sockaddr;
    19 
    20     sockfd = socket(AF_INET, SOCK_STREAM, 0);
    21     bzero(&sockaddr,sizeof(sockaddr));
    22     sockaddr.sin_family = AF_INET;
    23     sockaddr.sin_port = htons(serv_port);
    24     inet_pton(AF_INET, serv_ip, &sockaddr.sin_addr);
    25 
    26     rtn = connect(sockfd,(struct sockaddr *)&sockaddr, sizeof(sockaddr));
    27 
    28     if (rtn == INVALID)
    29     {
    30         puts("connection failure
    ");
    31         exit(1);
    32     }
    33     else
    34     {
    35         puts("connection successful
    ");
    36         return sockfd;
    37     }
    38 }
    39 
    40 int
    41 main(int argc, const char *argv[])
    42 {
    43     int i,read_size, sockfd = socket_setup(argv[1],argv[2]);
    44     char buffer[BUF_SIZE];
    45     fd_set fdset;
    46 
    47     while (1)
    48     {
    49         FD_ZERO(&fdset);
    50         FD_SET(STDIN, &fdset);
    51         FD_SET(sockfd, &fdset);
    52         select(sockfd + 1, &fdset, NULL, NULL, 0);
    53 
    54         if( FD_ISSET( sockfd, &fdset ) )
    55         {
    56             readsize = read(sockfd, buffer, BUF_SIZE);
    57             write(STOUT, buffer, read_size);
    58 
    59             if(read_size == 0)
    60             {
    61                 puts("server close");
    62                 exit(1);
    63             }
    64         }
    65 
    66         if(FD_ISSET(STDIN, &fdset))
    67         {
    68             read_size = read(STDIN, buffer, BUF_SIZE);
    69             write(sockfd, buffer, read_size);
    70         }
    71     }
    72 
    73     return 0;
    74 }

    2.聊天室程序——服务器端

     我的想法是,只要建立一个数组来存放客户端信息,每次有客户端发送信息或者在服务器端有消息需要发出去,直接遍历每一个元素给每个客户端发一个就好,客户端只需要完成以下几件事:

     1.初始化,因为select的性质,每次检测完后会清空fdset,所以需要每一次都把所有连接上了客户端都重新加入进fdset,涉及函数void init_clients(void)int main(int argc,const char *argv[]

     2.检测有没有新的信息发上来了,如果有,并且可读,那就广播出去,涉及函数:void chat(fd_set fdset)void broadcast(char *msg)

     3.把所有发上来的信息按照时间格式化输出,这里学到了几个新函数,一个是int sprintf( char *buffer, const char *format, [ argument] … );可以格式化输出字符串和数字,一个是对世间的格式化,size_t strftime(char *strDest,size_t maxsize,const char *format,const struct tm *timeptr );这里涉及的函数:void stdmsg(int i, char *buffer, const char *msg)

    源程序是:

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 #include <unistd.h>
      5 #include <time.h>
      6 #include <sys/socket.h>
      7 #include <arpa/inet.h>
      8 
      9 #define TIME_SIZE 16 // 表示时间的字符串长度
     10 #define IP_SIZE 16 // IP 字符串长度
     11 #define BUF_SIZE 256 // 缓冲区大小
     12 #define CLIENT_SIZE 8 // 允许的客户端数量
     13 #define BACKLOG CLIENT_SIZE // listen 队列长度,等于允许的客户端数量
     14 #define INVALID -1
     15 
     16 struct CLIENT{
     17     int clienfd;
     18     struct sockaddr_in sockaddr;
     19     char ip[IP_SIZE];
     20     int port;
     21 }clients[CLIENT_SIZE];
     22 
     23 void init_clients(void)
     24 {
     25     int i;
     26 
     27     for( i = 0; i < CLIENT_SIZE; i++ )
     28     {
     29         clients[i].clientfd = INVALID;
     30     }
     31 }
     32 
     33 void broadcast(char *msg)
     34 {
     35     int i;
     36 
     37     for(i = 0; i<CLIENT_SIZE; i++)
     38     {
     39         if( clients[i].clienfd != INVALID )
     40         {
     41             write(clients[i].clientfd, msg, sterlen(msg));
     42         }
     43     }
     44 }
     45 
     46 void stdmsg(int i, char *buffer, const char *msg)
     47 {
     48     char curtime[TIME_SIZE];
     49     time_t curtime_t;
     50     struct tm *timeinfo;
     51 
     52     curtime_t = time(NULL);
     53     timeinfo = localtime(&curtime_t);
     54     strftime(curtime, TIME_SIZE, "%X", timeinfo);
     55     sprintf(buffer,"<%s %s:%d> %s",curtime,clients[i].ip,clients[i].port,msg);
     56 }
     57 
     58 void accept_connect(int listenfd)
     59 {
     60     int connectfd,i;
     61     char buffer[BUF_SIZE];
     62     struct sockaddr_in clientaddr;
     63     socklen_t connectlen = sizeof(struct sockaddr_in);
     64 
     65     connectfd = accept( listenfd, (struct sockaddr_in *)&clientaddr, &connectlen);
     66 
     67 
     68     for( i = 0; i < CLIENT_SIZE, i++ )
     69     {
     70         if(clients[i].clienfd == INVALID)
     71         {
     72             clients[i].clienfd == connectfd;
     73             memcpy(&clients[i].sockaddr);
     74             clients[i].port = ntohs(clients[i].sockaddr.sin_port);
     75             inet_ntop(AF_INET, &clients[i].sockaddr.sin_addr, clients[i].ip, IP_SIZE);
     76             stdmsg(i,buffer,"login
    ");
     77             printf("%s",buffer);
     78             broadcast(buffer);
     79             break;
     80         }
     81     }
     82 
     83     if (i == CLIENT_SIZE )
     84     {
     85         strcpy(buffer, "out of number
    ");
     86         write(connectfd, buffer, strlen(buffer));
     87         close(connectfd);//所有操作利用buffer进行操作
     88     }
     89 }
     90 
     91 
     92 void chat(fd_set fdset)
     93 {
     94     int sockfd, read_size, i;
     95     char read_buf[BUF_SIZE], send_buf[BUF_SIZE];
     96 
     97     for( i = 0; i < CLIENT_SIZE; i++ )
     98     {
     99         sockfd = clients[i].clienfd;
    100 
    101         if(sockfd != INVALID && FD_ISSET(sockfd,&fdset))
    102         {
    103             read_size = read(sockfd, read_buf, BUF_SIZE - 1);
    104 
    105             if(read_size == 0)
    106             {
    107                 //connection lost
    108                 close(sockfd);
    109                 clients[i].clienfd = INVALID;
    110                 stdmsg(i, send_buf, "logout
    ");
    111                 printf("%s
    ",send_buf);
    112                 broadcast(send_buf);
    113 
    114                 continue;
    115             }
    116             else
    117             {
    118                 read_buf[read_size] = '';
    119                 stdmsg(i, send_buf, read_buf);
    120                 printf("%s",send_buf);
    121                 broadcast(send_buf);
    122             }
    123         }
    124     }
    125 }
    126 
    127 int socket_setup(int port)
    128 {
    129     int rtn, listenfd = socket(AF_INET, SOCK_STREAM, 0);
    130     struct sockaddr_in sockaddr;
    131 
    132     bzero(&sockaddr, sizeof(sockaddr));
    133     sockaddr.sin_family = AF_INET;
    134     sockaddr.sin_port = htons(port);
    135     sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    136 
    137     rtn = bind(listenfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
    138     if (rtn == INVALID)
    139     {
    140         puts("bind error
    ");
    141         exit(1);
    142     }
    143 
    144     if(listen(listenfd,BACKLOG) == INVALID)
    145     {
    146         puts("listen error
    ")
    147         exit(1);
    148     }
    149 
    150     puts("service setup
    ");
    151     return listenfd;
    152 }
    153 
    154 int main(int argc,const char *argv[])
    155 {
    156     int maxfd, i, listenfd = socket_setup(atoi(argv[1]));
    157     fdset fdset;
    158 
    159     init_clients();
    160 
    161     while(1)
    162     {
    163         FD_ZERO(&fdset);
    164         FD_SET(listenfd, &fdset);
    165         maxfd = listenfd;
    166 
    167         for(i = 0; i < CLIENT_SIZE; i++)
    168         {
    169             if(clients[i].clienfd != INVALID)
    170             {
    171                 FD_SET(clients[i].clienfd, &fdset);
    172 
    173                 if(clients[i].clienfd > maxfd)
    174                 {
    175                     maxfd = clients[i].clienfd;
    176                 }
    177             }
    178         }
    179 
    180         select(maxfd + 1, &fdset, NULL, NULL, 0);
    181 
    182         if(FD_ISSET(listenfd, &fdset))
    183         {
    184             accept_connect(listenfd);
    185         }
    186         chat(fdset);
    187     }
    188     return 0;
    189 }
  • 相关阅读:
    js数组去重五种方法
    wm_concat 多行字符串拼接
    ORACLE WITH AS 简单用法
    layui laytpl 语法
    看懂Oracle执行计划
    GIT RM -R --CACHED 去掉已经托管在GIT上的文件
    sourceTree使用教程--拉取、获取
    SourceTree忽略文件和文件夹
    layui table 详细讲解
    利用POI实现下拉框级联
  • 原文地址:https://www.cnblogs.com/hyd-desert-camel/p/3534561.html
Copyright © 2020-2023  润新知