聊天小项目之多客户端聊天

第二步:多用户同时在线聊天

需求分析:能支持对个用户同时聊天,实现群聊功能;

方法分析:采用多线程处理方式。不同的客户端开启不同的工作线程,共享同一进程的内存信息。服务端转发某一客户端发送的信息给其他客户端,实现信息实时共享。

服务端代码:

# server.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <pthread.h>

#define MAXLINE 1000     //在一条消息中最大的输出字符数
#define LISTENQ 20       //最大监听队列
#define PORT 5000        //监听端口
#define MAXFD 20         //最大的在线用户数量

void *get_client(void *);    
int sockfd,i;
static int maxi=0;//maxi表示当前client数组中最大的用户的i值
static int client[MAXFD];

void recvandsend(void)           //监听转发线程入口函数
{
    int index=0;
    int nbytes=0;

    char buffer[1024];
    int len;
    int outindex=0;
    
	while(1)
    {
        if(maxi>0)
        {
            memset(buffer,0,sizeof(buffer));
            nbytes=0;            
            nbytes=read(client[index++],buffer,sizeof(buffer));
            printf("%d,%d\n",index,client[index]); 

            if(nbytes>0)
            {
                buffer[nbytes]='\0';
                printf("%s\n",buffer);
                outindex=0;
                while(outindex<maxi)
                if(write(client[outindex++],buffer,sizeof(buffer))==-1)
                {
                    fprintf(stderr,"WriteError:%s\n",strerror(errno));
                    exit(1);
                }
            }
        }
        if(index>=maxi)
            index=0;
    }
    pthread_exit(NULL);
}
 
int main(int argc, char *argv[])
{
//     intclient_fd[LISTENQ],clientnum=0;;
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    int sin_size,portnumber;
    char hello[]="Hello! Are You Fine?\n";
    int        thr_id;         /* thread ID for the newly createdthread */
    pthread_t  p_thread;       /* thread's structure                     */

    int new_fd=0;

    memset(client,0,sizeof(client));

    if(argc!=1)
    {
        fprintf(stderr,"Usage:%sportnumber\a\n",argv[0]);
        exit(1);
    }

    /* 服务器端开始建立 socket 描述符 */
    if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
    {
        fprintf(stderr,"Socketerror:%s\n\a",strerror(errno));
        exit(1);
    }

    /* 服务器端填充 sockaddr 结构 */
    bzero(&server_addr,sizeof(struct sockaddr_in));
    server_addr.sin_family=AF_INET;
    server_addr.sin_addr.s_addr=htonl(INADDR_ANY);

    server_addr.sin_port=htons(PORT);
    /* 捆绑 sockfd 描述符 */
    if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
    {
        fprintf(stderr,"Binderror:%s\n\a",strerror(errno));
        exit(1);
    }
    printf("服务器监听端口%d...\n",PORT);
    /* 监听 sockfd 描述符 */
    if(listen(sockfd,LISTENQ)==-1)
    {
        fprintf(stderr,"Listenerror:%s\n\a",strerror(errno));
        exit(1);
    }
    thr_id =pthread_create(&p_thread, NULL, recvandsend, NULL);
    printf("欢迎来到本聊天室\n");

    while(1)
    {
    /* 服务器阻塞,直到客户程序建立连接 */
        if(maxi>=20)
        {
            printf("以达到人数上线\n");
            continue;
        }
        sin_size=sizeof(struct sockaddr_in);
        if((new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size))==-1)
        {
            fprintf(stderr,"Accepterror:%s\n\a",strerror(errno));
            exit(1);
        }
        /*fprintf(stderr,"Serverget connection from %s\n",inet_ntoa(client_addr.sin_addr));*/
        client[maxi++]=new_fd;
        printf("\n新用户进入聊天室%d\n",new_fd);      
    }
    close(sockfd);
    exit(0);
}

客户端代码:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <pthread.h>

#define TRUE 1
#define PORT 5000

static int sockfd;

void* recvfromserver()        //接受服务器消息线程入口函数
{
    char mes[1024];
    int nbytes=0;
    while(1)
    {
	    memset(mes, 0, sizeof(mes));
        nbytes = read(sockfd, mes, sizeof(mes));

   	    if(nbytes > 0)
	    {
		    mes[nbytes] = '\0';
			printf("%s\n", mes);
	    }
    }
    pthread_exit(NULL);
	return NULL;
}

int main(int argc, char *argv[])
{
   char   buffer[1024];
   struct sockaddr_in server_addr;
   struct hostent *host;
   int    portnumber,nbytes;
   char   strhost[16];
   char   clientname[20];
   char   mes[1024];
   int    thr_id;         /* thread ID for the newly createdthread */
   pthread_t  p_thread;       /* thread's structure                     */
   if(argc!=1)
   {
		fprintf(stderr,"Usage:%s\a\n",argv[0]);
		exit(1);
   }
   printf("请输入服务器ip地址\n");
   scanf("%s",strhost);
   if((host = gethostbyname(strhost)) == NULL)
   {
		fprintf(stderr,"Gethostnameerror\n");
		exit(1);
   }

   /* 客户程序开始建立 sockfd 描述符 */
   printf("正在建立套接口...\n");
   if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
   {
		fprintf(stderr,"SocketError:%s\a\n",strerror(errno));
		exit(1);
   }
   /* 客户程序填充服务端的资料 */
   bzero(&server_addr,sizeof(server_addr));
   server_addr.sin_family=AF_INET;
   server_addr.sin_port=htons(PORT);
   server_addr.sin_addr=*((struct in_addr *)host->h_addr);
   printf("套接口创建成功,正在链接服务器...\n");
   
   /* 客户程序发起连接请求 */
   if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
   {
		  fprintf(stderr,"ConnectError:%s\a\n",strerror(errno));
		  exit(1);
   }

   /* 连接成功了 */
   printf("链接服务器成功\n欢迎来到聊天室\n");
   printf("请输入你的用户昵称\n");
   scanf("%s",clientname);

//     write(sockfd,clientname,sizeof(clientname));
   printf("\n\n开始聊天吧(\"Quit\"断开连接)\n\n");
   thr_id = pthread_create(&p_thread, NULL, recvfromserver, NULL);
   while(1)
   {
		memset(buffer,0,sizeof(buffer));
		memset(mes,0,sizeof(mes));

		scanf("%s",buffer);            
		strcat(mes,clientname);
		strcat(mes,":");

		strcat(mes,buffer);

		if((write(sockfd,mes,sizeof(mes)))==-1)
		{
			fprintf(stderr,"WriteError:%s\n",strerror(errno));
			exit(1);
		}

		if(strcmp(buffer,"Quit")==0)
		{
			break;
		}
	}

   /* 结束通讯 */

   close(sockfd);
   exit(0);
}
# client.c

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <pthread.h>

#define TRUE 1
#define PORT 5000

static int sockfd;

void* recvfromserver()        //接受服务器消息线程入口函数
{
    char mes[1024];
    int nbytes=0;
    while(1)
    {
	    memset(mes, 0, sizeof(mes));
        nbytes = read(sockfd, mes, sizeof(mes));

   	    if(nbytes > 0)
	    {
		    mes[nbytes] = '\0';
			printf("%s\n", mes);
	    }
    }
    pthread_exit(NULL);
	return NULL;
}

int main(int argc, char *argv[])
{
   char   buffer[1024];
   struct sockaddr_in server_addr;
   struct hostent *host;
   int    portnumber,nbytes;
   char   strhost[16];
   char   clientname[20];
   char   mes[1024];
   int    thr_id;         /* thread ID for the newly createdthread */
   pthread_t  p_thread;       /* thread's structure                     */
   if(argc!=1)
   {
		fprintf(stderr,"Usage:%s\a\n",argv[0]);
		exit(1);
   }
   printf("请输入服务器ip地址\n");
   scanf("%s",strhost);
   if((host = gethostbyname(strhost)) == NULL)
   {
		fprintf(stderr,"Gethostnameerror\n");
		exit(1);
   }

   /* 客户程序开始建立 sockfd 描述符 */
   printf("正在建立套接口...\n");
   if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
   {
		fprintf(stderr,"SocketError:%s\a\n",strerror(errno));
		exit(1);
   }
   /* 客户程序填充服务端的资料 */
   bzero(&server_addr,sizeof(server_addr));
   server_addr.sin_family=AF_INET;
   server_addr.sin_port=htons(PORT);
   server_addr.sin_addr=*((struct in_addr *)host->h_addr);
   printf("套接口创建成功,正在链接服务器...\n");
   
   /* 客户程序发起连接请求 */
   if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
   {
		  fprintf(stderr,"ConnectError:%s\a\n",strerror(errno));
		  exit(1);
   }

   /* 连接成功了 */
   printf("链接服务器成功\n欢迎来到聊天室\n");
   printf("请输入你的用户昵称\n");
   scanf("%s",clientname);

//     write(sockfd,clientname,sizeof(clientname));
   printf("\n\n开始聊天吧(\"Quit\"断开连接)\n\n");
   thr_id = pthread_create(&p_thread, NULL, recvfromserver, NULL);
   while(1)
   {
		memset(buffer,0,sizeof(buffer));
		memset(mes,0,sizeof(mes));

		scanf("%s",buffer);            
		strcat(mes,clientname);
		strcat(mes,":");

		strcat(mes,buffer);

		if((write(sockfd,mes,sizeof(mes)))==-1)
		{
			fprintf(stderr,"WriteError:%s\n",strerror(errno));
			exit(1);
		}

		if(strcmp(buffer,"Quit")==0)
		{
			break;
		}
	}

   /* 结束通讯 */

   close(sockfd);
   exit(0);
}

部分代码来源网络,若有侵权,请联系作者删除。欢迎大家共享、交流。

发布了91 篇原创文章 · 获赞 75 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/fengxianghui01/article/details/104214657