用c寫一個小的聊天室程序

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

客戶端我也用了select進(jìn)行I/O復(fù)用乙濒,同時監(jiān)控是否有來自socket的消息和標(biāo)準(zhǔn)輸入陕赃,近似可以完成對鍵盤的中斷使用。

其中select的監(jiān)控里颁股,STDOUT和STDIN是已有規(guī)定的值了么库。

Socket_setup函數(shù)負(fù)責(zé)進(jìn)行對socket進(jìn)行初始化完成connect 的過程,然后在主函數(shù)里無限循環(huán)檢查sockfd和STDIN的緩沖區(qū)是否有新的消息

客戶端程序較簡單:

復(fù)制代碼
 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\n");
31         exit(1);
32     }
33     else
34     {
35         puts("connection successful\n");
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 }
	

復(fù)制代碼

2.聊天室程序——服務(wù)器端

我的想法是甘有,只要建立一個數(shù)組來存放客戶端信息诉儒,每次有客戶端發(fā)送信息或者在服務(wù)器端有消息需要發(fā)出去,直接遍歷每一個元素給每個客戶端發(fā)一個就好亏掀,客戶端只需要完成以下幾件事:

1.初始化忱反,因為select的性質(zhì),每次檢測完后會清空fdset滤愕,所以需要每一次都把所有連接上了客戶端都重新加入進(jìn)fdset温算,涉及函數(shù)void init_clients(void),int main(int argc,const char *argv[]

2.檢測有沒有新的信息發(fā)上來了间影,如果有注竿,并且可讀,那就廣播出去,涉及函數(shù):void chat(fd_set fdset)巩割,void broadcast(char *msg)

3.把所有發(fā)上來的信息按照時間格式化輸出裙顽,這里學(xué)到了幾個新函數(shù),一個是int sprintf( char *buffer, const char *format, [ argument] … );可以格式化輸出字符串和數(shù)字喂分,一個是對世間的格式化锦庸,size_t strftime(char *strDest,size_t maxsize,const char *format,const struct tm *timeptr );這里涉及的函數(shù):void stdmsg(int i, char *buffer, const char *msg)

源程序是:

復(fù)制代碼
  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 // 緩沖區(qū)大小
 12 #define CLIENT_SIZE 8 // 允許的客戶端數(shù)量
 13 #define BACKLOG CLIENT_SIZE // listen 隊列長度,等于允許的客戶端數(shù)量
 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\n");
 77             printf("%s",buffer);
 78             broadcast(buffer);
 79             break;
 80         }
 81     }
 82 
 83     if (i == CLIENT_SIZE )
 84     {
 85         strcpy(buffer, "out of number\n");
 86         write(connectfd, buffer, strlen(buffer));
 87         close(connectfd);//所有操作利用buffer進(jìn)行操作
 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\n");
111                 printf("%s\n",send_buf);
112                 broadcast(send_buf);
113 
114                 continue;
115             }
116             else
117             {
118                 read_buf[read_size] = '\0';
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\n");
141         exit(1);
142     }
143 
144     if(listen(listenfd,BACKLOG) == INVALID)
145     {
146         puts("listen error\n")
147         exit(1);
148     }
149 
150     puts("service setup\n");
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 }
		

復(fù)制代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蒲祈,一起剝皮案震驚了整個濱河市甘萧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌梆掸,老刑警劉巖扬卷,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異酸钦,居然都是意外死亡怪得,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門卑硫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來徒恋,“玉大人,你說我怎么就攤上這事欢伏∪胝酰” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵硝拧,是天一觀的道長径筏。 經(jīng)常有香客問我,道長障陶,這世上最難降的妖魔是什么滋恬? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮抱究,結(jié)果婚禮上恢氯,老公的妹妹穿的比我還像新娘。我一直安慰自己媳维,他們只是感情好酿雪,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著侄刽,像睡著了一般指黎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上州丹,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天醋安,我揣著相機與錄音杂彭,去河邊找鬼。 笑死吓揪,一個胖子當(dāng)著我的面吹牛亲怠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播柠辞,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼团秽,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了叭首?” 一聲冷哼從身側(cè)響起习勤,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎焙格,沒想到半個月后图毕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡眷唉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年予颤,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冬阳。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡蛤虐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出肝陪,到底是詐尸還是另有隱情笆焰,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布见坑,位于F島的核電站,受9級特大地震影響捏检,放射性物質(zhì)發(fā)生泄漏荞驴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一贯城、第九天 我趴在偏房一處隱蔽的房頂上張望熊楼。 院中可真熱鬧,春花似錦能犯、人聲如沸鲫骗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽执泰。三九已至,卻和暖如春渡蜻,著一層夾襖步出監(jiān)牢的瞬間术吝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留叛甫,地道東北人袁铐。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像淘衙,于是被迫代替她去往敵國和親传藏。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容

  • 大綱 一.Socket簡介 二.BSD Socket編程準(zhǔn)備 1.地址 2.端口 3.網(wǎng)絡(luò)字節(jié)序 4.半相關(guān)與全相...
    y角閱讀 2,380評論 2 11
  • 轉(zhuǎn)自http://blog.csdn.net/xugangwen/article/details/44811783...
    扎Zn了老Fe閱讀 12,693評論 1 142
  • 是誰把藍(lán)天偷偷藏了起來彤守, 又是誰告訴我毯侦, 天空本來就很藍(lán), 是誰把我的眼睛遮住遗增, 我使勁的想推開叫惊, 可還是看不見,...
    墨筆生徽閱讀 1,164評論 6 3
  • 春天的腳步近了做修。樹上盛滿了花霍狰,兩周路過,有種隔世的錯覺饰及。似乎昨日還是花苞蔗坯,今日就已開的燦爛。我驚異于這變化燎含,感慨“...
    昈_閱讀 211評論 0 3
  • 今天和女兒和老公一塊走了娘家,女兒特高興赴魁,喜歡姥姥家的大山卸奉,還喜歡姥姥家的大水庫,蘋果樹……等等颖御。女兒到姥姥家特興...
    孫佳婧媽媽閱讀 198評論 0 0