【linux】マルチチャットルーム実現
一、設計構想
サーバはクライアントからの接続要求を受信、クライアントからデータが送信された場合、
サーバは、グローバル・バッファにデータを保存し、接続されたクライアントにデータ・ループを送信します.
二、コード展示
1.サーバ側charroom_server_01.c
2.クライアントcharroom_client_01.c
三、コードコンパイル
四、実例プレゼンテーション
1.サーバーを起動する
2.最初のクライアント
3.2番目のクライアント
サーバはクライアントからの接続要求を受信、クライアントからデータが送信された場合、
サーバは、グローバル・バッファにデータを保存し、接続されたクライアントにデータ・ループを送信します.
二、コード展示
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: