【linux】マルチチャットルーム実現


一、設計構想
サーバはクライアントからの接続要求を受信、クライアントからデータが送信された場合、
サーバは、グローバル・バッファにデータを保存し、接続されたクライアントにデータ・ループを送信します.
二、コード展示
1.サーバ側charroom_server_01.c
#include <stdio.h>
#include <string.h>
#include <sys/select.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>  //for INADDR_ANY

#define MAX_CLIENT_NUM 10	/*          */
#define MAXLENGHT 1024		/*        */
#define SERVER_PORT 5012	/*          */
#define LISTEN_MAX_NUM 5	/*          */

int main(void)
{
	int clientSocket = -1, listenSocket = -1;
	int client[MAX_CLIENT_NUM];
	char buf[MAXLENGHT] = {0};
	fd_set allset, rset;
	socklen_t clilen;
	struct sockaddr_in cliaddr,  seraddr;
	int i = -1, maxi = -1, maxfd = -1, ret = -1, reuse = -1, iReady = -1;
	struct timeval tv;
	
	/*   TCP  socket */
	listenSocket = socket(AF_INET, SOCK_STREAM, 0);
	if (-1 == listenSocket)
	{
		printf("create socket error: %s
",strerror(errno)); return -1; } else { printf("listenSocket = %d
", listenSocket); } bzero(&seraddr, sizeof(seraddr)); seraddr.sin_family = AF_INET; seraddr.sin_addr.s_addr = htonl(INADDR_ANY); seraddr.sin_port = htons(SERVER_PORT); /* */ reuse = 1; ret = setsockopt(listenSocket,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)); if (0 > ret) { printf("setsockopt error: %s
",strerror(errno)); return -1; } /* IP */ ret = bind(listenSocket, (struct sockaddr *)&seraddr, sizeof(seraddr)); if (0 > ret) { printf("bind error: %s
",strerror(errno)); return -1; } /* */ ret = listen(listenSocket, LISTEN_MAX_NUM); if (0 > ret) { printf("listen error: %s
",strerror(errno)); return -1; } /* */ maxfd = listenSocket; memset(buf, 0 ,sizeof(buf)); for (i = 0; i < MAX_CLIENT_NUM; i++) client[i] = -1; FD_ZERO(&allset); FD_SET(listenSocket, &allset); /* set two seconds to timeout */ //tv.tv_sec = 2; //tv.tv_usec = 0; for (;;) { //iReady = select(maxfd + 1, &allset, NULL, NULL, &tv); // allset , ,if (FD_ISSET(fd, &rset)) , rset rset = allset; iReady = select(maxfd + 1, &rset, NULL, NULL, NULL); if (0 > iReady) { printf("select error: %s, errno: %d
",strerror(errno), errno); return -1; } else if (0 == iReady) // { printf("no data within two seconds.
"); continue; } else { printf("iReady=%d
", iReady); } /* */ if (FD_ISSET(listenSocket, &rset)) { /* */ clilen = sizeof(cliaddr); clientSocket = accept(listenSocket, (struct sockaddr *)&cliaddr, &clilen); printf("clientSocket : %d
", clientSocket); if (-1 == clientSocket) { printf("accept error: %s
",strerror(errno)); continue; } /* socket */ for (i = 0; i < MAX_CLIENT_NUM; i++) { if (client[i] < 0) { client[i] = clientSocket; break; } } FD_SET(clientSocket, &allset); if (clientSocket > maxfd) maxfd = clientSocket; if (i > maxi) // maxi maxi = i; } /* */ for (i = 0; i <= maxi; i++) { int fd = -1, n = -1; if ((fd = client[i]) < 0) continue; /* FD_ISSET true, fd rset , fd */ if (FD_ISSET(fd, &rset)) { for (;;) { // , memset(buf, 0, sizeof(buf)); n = recv(fd, buf, sizeof(buf), 0); if ( n < 0) { printf("recv error: %s
",strerror(errno)); if(errno == EAGAIN) continue; else break;; } else if (n == 0) // socket { printf("client close: %d
", fd); close(fd); FD_CLR(fd, &allset); client[i] = -1; break; } if (n != sizeof(buf)) // { printf("recv:%s
", buf); // int j = 0, size = 0, fd2 = -1; for (j = 0; j <= maxi; j++) { if ((fd2 = client[j]) < 0) continue; char tmp[MAXLENGHT] = {0}; snprintf(tmp, sizeof(tmp), "%d say: %s", i, buf); size = send(fd2, tmp, strlen(tmp), 0); //printf("send: %s, size: %d, n: %d, fd2:%d
", buf, size, n, fd2); if (size < 0) { printf("send error: %s
",strerror(errno)); continue; } } break; } else { continue; // , } } } } } }

2.クライアントcharroom_client_01.c
#include <stdio.h>
#include <string.h>
#include <sys/select.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>  //for INADDR_ANY
#include <pthread.h>

#define SERVER_PORT 5012	/*          */
#define MAX_LENGTH 1024     /*        */

/*                 
 * 1            ,         
 * 0           */
static int g_iIsSend = 0;

/*       */
char sendBuf[MAX_LENGTH] = {0};

/*              
 * 1         
 * 0       
 */
static int g_iWait = 1;

/*        */
void *recevie_user_input(void *arg);

int main(void)
{
	int sockfd = -1, ret = -1, i = -1;
	struct sockaddr_in servaddr;
	char buf[MAX_LENGTH] = {0};
	int n = -1;
	pthread_t tid;
	pthread_attr_t attr;
	
	/*   socket s*/
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (-1 == sockfd)
	{
		printf("create socket error: %s
",strerror(errno)); return -1; } bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(SERVER_PORT); inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr); ret = connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); if (-1 == ret) { printf("connect socket error: %s
",strerror(errno)); return -1; } pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); // if (pthread_create(&tid, &attr, recevie_user_input, NULL) != 0) { printf("create thread error.
"); return -1; } while(1) { /* 1 == g_iIsSend, sendBuf, */ if (1 == g_iIsSend) { n = send(sockfd, sendBuf, strlen(sendBuf), 0); if (n < 0) { printf("send error: %s
",strerror(errno)); break; } g_iIsSend = 0; continue; } /* , , , , , while(1) */ memset(buf, 0, sizeof(buf)); // MSG_DONTWAIT, EAGAIN n = recv(sockfd, buf, sizeof(buf), MSG_DONTWAIT); if ( n < 0) { if(errno == EAGAIN) continue; else break;; } else if (n == 0) // { close(sockfd); sockfd = -1; } /* 1 == g_iWait , , */ if (1 == g_iWait) { printf("
"); printf("\033[1A"); // printf("\033[K"); // “"please input:” } /* , “"please input:”*/ printf("%s", buf); if (1 == g_iWait) { printf("please input:"); fflush(stdout); } } if (sockfd < 0) { close(sockfd); sockfd = -1; } return 0; } /* * CTRL + Backspace : * CTRL + U: */ void *recevie_user_input(void *arg) { int i = -1; while(1) { /* , "
" */ //setbuf(stdout, NULL); if (0 == g_iIsSend) { /* */ printf("please input:"); // , , fflush(stdout); g_iWait = 1; memset(sendBuf, 0, sizeof(sendBuf)); read(STDIN_FILENO, sendBuf, sizeof(sendBuf)); g_iWait = 0; // /* * \e[ \033[ CSI, 。 * \e[K EOL ( ) * \e[NX X N,X = A( ) / B( ) / C( ) / D( ),\e[1A 1 */ printf("\033[1A"); // printf("\033[K"); // g_iIsSend = 1; } } }

三、コードコンパイル
[root@f8s charroom]# gcc charroom_server_01.c -o charroom_server_01

[root@f8s charroom]# gcc charroom_client_01.c -o charroom_client_01 -lpthread

四、実例プレゼンテーション
1.サーバーを起動する
[root@f8s charroom]# ./charroom_server_01
listenSocket = 3

2.最初のクライアント
[root@f8s charroom]# ./charroom_client_01
0 say: hi
0 say: i'm zhangshan
1 say: hello
1 say: my name is lisi.
0 say: nice to meet you.
1 say: nice to meet you.
please input:

3.2番目のクライアント
[root@f8s charroom]# ./charroom_client_01
1 say: hello
1 say: my name is lisi.
0 say: nice to meet you.
1 say: nice to meet you.
please input: