linux socketチャットルーム
34776 ワード
linux socketチャットルームは、もともと自分でやるべきことではなく、他の人の宿題を完成させるためです.ちょうど最近の授業はsocketプログラミングについてですが、手の練習に来ませんか.
SOcketベースのチャットルームは、入学当初から似たようなことをしていたが、当時使っていたjavaで実現されただけで、正式にSOcketを学んだことがないため、コードは他人のものを転用しただけで、深く理解していなかった.
単一ユーザ-サービスの会話は、マルチユーザ-サービスであっても、連続サービスでない限り、サービス側はポーリングによって複数のユーザにサービスを提供することができる.問題は、一般的なsocket I/O関数の多くがブロックされていることです.これは、単一のスレッドが1人のユーザーにしかサービスできないことを意味します.したがって、マルチスレッドを使用することは自然に考えられますが、マルチスレッドは最適な解決策ではありません.結局、頻繁にスレッドを作成し、破棄すると、一定の浪費をもたらします.selectの多重化を利用すれば、よりよく解決できます.
クライアント実装
クライアントはよく実現され、2つのI/Oだけが通信し、server socketとstdinであり、fd値が固定されており、maxfdpは直接socket+1を取ればよい.
サービス側実装
このチャットルームの実現の難点はサービス側であり,マルチユーザチャットをサポートできることである.
私の実装方法は,接続された顧客情報を1つの構造体配列clientsで保存し,配列を巡る方式でメッセージをブロードキャストすることであり,一般的にはこの点を考えることができ,selectによる多重化に重点を置いている.
お客様のsocketはダイナミックなので、お客様の接続/切断に注意して処理する必要があります.ユーザー接続がある場合はsocketを保存し、接続を切断した後、socket値を無効にします.
SOcketベースのチャットルームは、入学当初から似たようなことをしていたが、当時使っていたjavaで実現されただけで、正式にSOcketを学んだことがないため、コードは他人のものを転用しただけで、深く理解していなかった.
単一ユーザ-サービスの会話は、マルチユーザ-サービスであっても、連続サービスでない限り、サービス側はポーリングによって複数のユーザにサービスを提供することができる.問題は、一般的なsocket I/O関数の多くがブロックされていることです.これは、単一のスレッドが1人のユーザーにしかサービスできないことを意味します.したがって、マルチスレッドを使用することは自然に考えられますが、マルチスレッドは最適な解決策ではありません.結局、頻繁にスレッドを作成し、破棄すると、一定の浪費をもたらします.selectの多重化を利用すれば、よりよく解決できます.
クライアント実装
クライアントはよく実現され、2つのI/Oだけが通信し、server socketとstdinであり、fd値が固定されており、maxfdpは直接socket+1を取ればよい.
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 // stdinfd
11 #define STDOUT 1 // stdoutfd
12 #define INVALID -1
13
14 /** socket , */
15 int socket_setup(const char *serv_ip, int serv_port)
16 {
17 int rtn, sockfd = socket(AF_INET, SOCK_STREAM, 0);
18 struct sockaddr_in sockaddr;
19
20 bzero(&sockaddr, sizeof(sockaddr));
21 sockaddr.sin_family = AF_INET;
22 sockaddr.sin_port = htons(serv_port);
23 inet_pton(AF_INET, serv_ip, &sockaddr.sin_addr);
24
25 rtn = connect(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
26
27 if (rtn == INVALID)
28 {
29 puts("Connection failure");
30 exit(1);
31 }
32 else
33 {
34 puts("Connection successful");
35 return sockfd;
36 }
37 }
38
39 int main(int argc, const char *argv[])
40 {
41 int i, read_size, sockfd = socket_setup(argv[1], atoi(argv[2]));
42 char buffer[BUF_SIZE];
43 fd_set fdset;
44
45 while (true)
46 {
47 FD_ZERO(&fdset);
48 FD_SET(STDIN, &fdset);
49 FD_SET(sockfd, &fdset);
50 select(sockfd + 1, &fdset, NULL, NULL, NULL);
51
52 /** socket -> */
53 if (FD_ISSET(sockfd, &fdset))
54 {
55 read_size = read(sockfd, buffer, BUF_SIZE);
56 write(STDOUT, buffer, read_size);
57
58 if (read_size == 0)
59 {
60 puts("Server close");
61 exit(1);
62 }
63 }
64
65 /** -> socket */
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 }
サービス側実装
このチャットルームの実現の難点はサービス側であり,マルチユーザチャットをサポートできることである.
私の実装方法は,接続された顧客情報を1つの構造体配列clientsで保存し,配列を巡る方式でメッセージをブロードキャストすることであり,一般的にはこの点を考えることができ,selectによる多重化に重点を置いている.
お客様のsocketはダイナミックなので、お客様の接続/切断に注意して処理する必要があります.ユーザー接続がある場合はsocketを保存し、接続を切断した後、socket値を無効にします.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <stdbool.h>
5 #include <unistd.h>
6 #include <time.h>
7 #include <sys/socket.h>
8 #include <arpa/inet.h>
9
10 #define TIME_SIZE 16 //
11 #define IP_SIZE 16 // IP
12 #define BUF_SIZE 256 //
13 #define CLIENT_SIZE 8 //
14 #define BACKLOG CLIENT_SIZE // listen ,
15 #define INVALID -1
16
17 /** */
18 struct CLIENT {
19 int clientfd;
20 struct sockaddr_in sockaddr;
21 char ip[IP_SIZE];
22 int port;
23 } clients[CLIENT_SIZE];
24
25 /** */
26 void init_clients(void)
27 {
28 int i;
29
30 for (i = 0; i< CLIENT_SIZE; i++)
31 clients[i].clientfd = INVALID;
32 }
33
34 /** */
35 void broadcast(char *msg)
36 {
37 int i;
38
39 for (i = 0; i< CLIENT_SIZE; i++)
40 if (clients[i].clientfd != INVALID)
41 write(clients[i].clientfd, msg, strlen(msg));
42 }
43
44 /** */
45 void strfmsg(int i, char *buffer, const char *msg)
46 {
47 char curtime[TIME_SIZE];
48 time_t curtime_t;
49 struct tm *timeinfo;
50
51 time(&curtime_t);
52 timeinfo = localtime(&curtime_t);
53 strftime(curtime, TIME_SIZE, "%X", timeinfo);
54
55 sprintf(
56 buffer,
57 "<%s %s:%d> %s",
58 curtime,
59 clients[i].ip,
60 clients[i].port,
61 msg);
62 }
63
64 /** */
65 void accept_connect(int listenfd)
66 {
67 int connectfd, i;
68 char buffer[BUF_SIZE];
69 struct sockaddr_in clientaddr;
70 socklen_t connectlen = sizeof(struct sockaddr_in);
71
72 connectfd = accept(
73 listenfd,
74 (struct sockaddr *)&clientaddr,
75 &connectlen);
76
77 /** */
78 for (i = 0; i < CLIENT_SIZE; i++)
79 {
80 if (clients[i].clientfd == INVALID)
81 {
82 clients[i].clientfd = connectfd;
83 memcpy(&clients[i].sockaddr, &clientaddr, connectlen);
84 clients[i].port = ntohs(clients[i].sockaddr.sin_port);
85 inet_ntop(
86 AF_INET,
87 &clients[i].sockaddr.sin_addr,
88 clients[i].ip,
89 IP_SIZE);
90
91 strfmsg(i, buffer, "login
");
92 printf("%s", buffer);
93 broadcast(buffer);
94
95 break;
96 }
97 }
98
99 /** */
100 if (i == CLIENT_SIZE)
101 {
102 strcpy(buffer, "Out of Number
");
103 write(connectfd, buffer, strlen(buffer));
104 close(connectfd);
105 }
106 }
107
108 /** */
109 void chat(fd_set fdset)
110 {
111 int sockfd, read_size, i;
112 char read_buf[BUF_SIZE], send_buf[BUF_SIZE];
113
114 for (i = 0; i < CLIENT_SIZE; i++)
115 {
116 sockfd = clients[i].clientfd;
117
118 if (sockfd != INVALID && FD_ISSET(sockfd, &fdset))
119 {
120 read_size = read(sockfd, read_buf, BUF_SIZE - 1);
121
122 if (read_size == 0)
123 {
124 /** */
125 close(sockfd);
126 clients[i].clientfd = INVALID;
127
128 strfmsg(i, send_buf, "logout
");
129 printf("%s", send_buf);
130 broadcast(send_buf);
131
132 continue;
133 }
134 else
135 {
136 read_buf[read_size] = '\0';
137 strfmsg(i, send_buf, read_buf);
138 printf("%s", send_buf);
139 broadcast(send_buf);
140 }
141 }
142 }
143 }
144
145 /** socket , */
146 int socket_setup(int port)
147 {
148 int rtn, listenfd = socket(AF_INET, SOCK_STREAM, 0);
149 struct sockaddr_in sockaddr;
150
151 bzero(&sockaddr, sizeof(sockaddr));
152 sockaddr.sin_family = AF_INET;
153 sockaddr.sin_port = htons(port);
154 sockaddr.sin_addr.s_addr= htonl(INADDR_ANY);
155
156 rtn = bind(listenfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
157
158 if (rtn == INVALID)
159 {
160 puts("Bind failure");
161 exit(1);
162 }
163
164 if (listen(listenfd, BACKLOG) == INVALID)
165 {
166 puts("Listen failure");
167 exit(1);
168 }
169
170 puts("Service startup");
171 return listenfd;
172 }
173
174 int main(int argc, const char *argv[])
175 {
176 int maxfdp, i, listenfd = socket_setup(atoi(argv[1]));
177 fd_set fdset;
178
179 init_clients();
180
181 while (true)
182 {
183 FD_ZERO(&fdset);
184 FD_SET(listenfd, &fdset);
185 maxfdp = listenfd;
186
187 /** socket fdset, maxfdp */
188 for (i = 0; i < CLIENT_SIZE; i++)
189 {
190 if (clients[i].clientfd != INVALID)
191 {
192 FD_SET(clients[i].clientfd, &fdset);
193
194 if (clients[i].clientfd > maxfdp)
195 maxfdp = clients[i].clientfd;
196 }
197 }
198
199 select(maxfdp + 1, &fdset, NULL, NULL, NULL);
200
201 if (FD_ISSET(listenfd, &fdset))
202 accept_connect(listenfd);
203
204 chat(fdset);
205 }
206
207 return 0;
208 }