Linux多人群聊系统(简单多线程服务器)

一:要求

  1.通过一个服务器实现最多5个客户之间的信息群发。

  2.服务器显示客户的登录与退出;

  3.客户连接后首先发送客户名称,之后发送群聊信息;

  4.客户输入bye代表退出,在线客户能显示其他客户的登录于退出。

二:提示

1、服务器端:

  主线程:

    定义一个全局客户信息表ent,每个元素对应一个客户,存储:socket描述符、客户名、客户IP、客户端口、状态(初值为0)。

    主线程循环接收客户连接请求,在ent中查询状态为0的元素,

    如果不存在状态为0的元素(即连接数超过最大连接数),向客户发送EXIT标志;

     否则,修改客户信息表中该元素的socket描述符、客户IP、客户端口号,状态为1(表示socket可用);

    同时创建一个通信线程并将客户索引号index传递给通信线程。

  通信线程:

    首先向客户端发送OK标志

    循环接收客户发来信息,若信息长度为0,表示客户端已关闭,向所有在线客户发送该用户退出;

    若信息为用户名,修改全局客户信息表ent中index客户的用户名name,并显示该用户登录;

    若信息为退出,修改全局客户信息表ent中index客户状态为0,并显示该用户退出,终止线程;

    同时查询全局客户信息表ent,向状态为1的客户发送接收的信息。

2、客户端:

    根据用户从终端输入的服务器IP地址及端口号连接到相应的服务器;

    连接成功后,接收服务端发来的信息,若为EXIT,则达到最大用户量,退出;

    若为OK,可以通讯,首先先发送客户名称;

    主进程循环从终端输入信息,并将信息发送给服务器;

    当发送给服务器为bye后,程序退出。

    同时创建一个线程负责接收服务器发来的信息,并显示,当接收的长度小于等于0时终止线程;

三:程序

     客户端与服务端的头文件:

ifndef _GCS_H
#define _GCS_H
#include <netinet/in.h>

#define MSGLEN  1024

#define OK   1
#define EXIT 2
#define MSG  3
#define USER 4

struct CLIENTMSG {
    int op;
    char user[20];
    char buf[MSGLEN];
};

struct CLIENTS {
    int sockfd;
    int port;
    char user[20];
    struct sockaddr_in client;
    int stat;
};
struct CLIENTS ent[5];

#endif

  

服务端:

  

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

extern struct CLIENTS ent[5];

void* func(void *arg);
void sever_process(int index);

int main(int argc, char **argv)
{
    int sever_fd,client_fd;
    struct sockaddr_in sever,client;
    char ip[20];
    int port,clientlen;
    unsigned char i,index;
    struct CLIENTMSG clientMSG;
    pthread_t tid;
    int *arg;

    for(i=0; i<5; i++) {
        ent[i].stat = 0;
    }

    /***************创建服务器sockfd************/
    if((sever_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket error");
        exit(errno);
    }

    /***************输入ip与端口*****************/
    printf("please input ip:");
    scanf("%s", ip);
    printf("\nplease input port:");
    scanf("%d", &port);
    printf("\n");

    /******************bind***********************/
    bzero(&sever, sizeof(sever));
    sever.sin_family = AF_INET;
    sever.sin_port   = htons(port);
    sever.sin_addr.s_addr= inet_addr(ip);
    if(bind(sever_fd, (struct sockaddr*)&sever, sizeof(struct sockaddr)) == -1) {
        perror("bind error");
        exit(errno);
    }

   /******************listen***********************/
   if(listen(sever_fd, 5) == -1) {
        perror("listen error");
        exit(errno);
   }

   while(1) {
    clientlen = sizeof(client);
    if((client_fd = accept(sever_fd, (struct sockaddr*)&client, &clientlen)) == -1) {
        perror("accept error");
        exit(errno);
    }
    printf("accept ok\n");
    index = 5;
    for(i=0; i<5; i++) {
        if(ent[i].stat ==0){
            index = i;
            break;
      }
    }

    if(index <= 4) {
        printf("client_fd : %d\n", client_fd);
        ent[index].sockfd = client_fd;
        ent[index].port   = port;
        ent[index].client = client;
        ent[index].stat   = 1;
        arg = malloc(sizeof(int));
        *arg = index;
        pthread_create(&tid, NULL, func, (void*)arg);
    } else {
        printf("the client already has 5\n");
        bzero(&clientMSG, sizeof(clientMSG));
        clientMSG.op = EXIT;
        send(client_fd, &clientMSG, sizeof(clientMSG), 0);
        close(client_fd);
    }

   }
    close(sever_fd);
    return 0;
}

void *func(void *arg)
{
    int *info;
    info = (int *)arg;
    sever_process(*info);
    pthread_exit(NULL);
}

void sever_process(int index)
{
    struct CLIENTMSG sendMSG;
    struct CLIENTMSG recvMSG;
    int len,i;

    /*首先发送邋OK标志*/
    sendMSG.op = OK;
    send(ent[index].sockfd, &sendMSG, sizeof(sendMSG), 0);

    while(1) {
        bzero(&sendMSG, sizeof(sendMSG));
        bzero(&recvMSG, sizeof(recvMSG));

        len = recv(ent[index].sockfd, &recvMSG, sizeof(recvMSG), 0);
        if(len == 0) {
            sendMSG.op = EXIT;
            for(i=0; i<5; i++) {
                if(ent[i].stat == 1)
                    send(ent[i].sockfd, &sendMSG, sizeof(sendMSG), 0);
            }
        }
        if(len > 0) {
            if(recvMSG.op == USER) {
                bcopy(recvMSG.user, ent[index].user, strlen(recvMSG.user));
                printf("user %s login form ip: %s   port: %d\n", ent[index].user, inet_ntoa(ent[index].client.sin_addr), ntohs(ent[index].client.sin_port));
                sendMSG.op = USER;
            }
            if(recvMSG.op == EXIT) {
                //printf("recv exit\n");
                sendMSG.op = EXIT;
                bcopy(ent[index].user, sendMSG.user, strlen(recvMSG.user));
                for(i=0; i<5; i++) {
                    if(ent[i].stat == 1)
                        send(ent[i].sockfd, &sendMSG, sizeof(sendMSG), 0);
                }
                break;
            }
            if(recvMSG.op == MSG) {
                //printf("recv msg\n");
                //printf("%s: %s", recvMSG.user,recvMSG.buf);
                sendMSG.op= MSG;
            }
            bcopy(recvMSG.user, sendMSG.user, strlen(recvMSG.user));
            bcopy(recvMSG.buf, sendMSG.buf, strlen(recvMSG.buf));
            for(i=0; i<5; i++) {
                //printf("\n%d: %s\n", sendMSG.op, sendMSG.user);
                if(ent[i].stat == 1) {
                    if(strncmp(ent[i].user, sendMSG.user, strlen(sendMSG.user)))
                        send(ent[i].sockfd, &sendMSG, sizeof(sendMSG), 0);
                }

            }
        }
    }

}

    

  客户端:

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

struct client_arg {
    int sockfd;
    struct CLIENTMSG clientMSG;
};
struct client_arg *arg;

void *func(void* arg);
void client_process(int sockfd, struct CLIENTMSG clientMSG);

int main(int argc, char **argv)
{
    int sockfd;
    struct sockaddr_in sever;
    char ip[20];
    unsigned int port,len;
    struct CLIENTMSG sendMSG;
    pthread_t tid;

    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket error");
        exit(1);
    }

    printf("please input ip:");
    scanf("%s", ip);
    printf("\nplease input port:");
    scanf("%d", &port);
    printf("\n");

    bzero(&sever, sizeof(sever));
    sever.sin_family = AF_INET;
    sever.sin_port = htons(port);
    inet_aton(ip, &sever.sin_addr);
    if(connect(sockfd, (struct sockaddr*)&sever, sizeof(struct sockaddr)) == -1) {
        perror("connect error");
        exit(errno);
    }

    len = recv(sockfd, &sendMSG, sizeof(sendMSG), 0);
    if(len > 0){
        if(sendMSG.op == EXIT) {
            printf("exceed the numble of users\n");
        }
        if(sendMSG.op == OK) {
            bzero(&sendMSG, sizeof(sendMSG));
            printf("please input client name: ");
            fgets(sendMSG.user, MSGLEN, stdin);
            //scanf("%s", sendMSG.user);
            sendMSG.op = USER;
            send(sockfd, &sendMSG, sizeof(sendMSG), 0);
            arg = (struct client_arg*)malloc(sizeof(struct client_arg));
            arg->sockfd = sockfd;
            pthread_create(&tid, NULL, func, (void*)arg);

            while(1) {
//                bzero(&sendMSG, sizeof(sendMSG));
                sendMSG.op = MSG;
                //printf("waiting...");
                fgets(sendMSG.buf, MSGLEN, stdin);
                //scanf("%s", sendMSG.buf);
                //printf("%s: %s  %d\n", sendMSG.user,sendMSG.buf, sendMSG.op);
                if(!strncasecmp(sendMSG.buf, "bye", 3)) {
                    sendMSG.op = EXIT;
                    send(sockfd, &sendMSG, sizeof(sendMSG), 0);
                    break;
                }
                send(sockfd, &sendMSG, sizeof(sendMSG), 0);
            }
        }
        pthread_cancel(tid);
    }
    close(sockfd);
    return 0;
}

void *func(void* arg)
{
    struct client_arg *info;
    info = (struct client_arg*)arg;
    client_process(info->sockfd, info->clientMSG);
    free(arg);
    pthread_exit(NULL);
}

void client_process(int sockfd, struct CLIENTMSG clientMSG)
{
    int len;
    while(1) {
        bzero(&clientMSG, sizeof(clientMSG));
        len = recv(sockfd, &clientMSG, sizeof(clientMSG), 0);
        if(len > 0) {
            if(clientMSG.op==USER){
                printf("the user %s is login.\n",clientMSG.user);
             }else if(clientMSG.op == EXIT){
                 printf("the user %s is logout.\n",clientMSG.user);
             }else if(clientMSG.op == MSG){
                printf("%s: %s\n",clientMSG.user,clientMSG.buf);
            }
        }
    }
}

  Makefile文件:

  

main:sever.o client.o
        gcc sever.o -o sever -lpthread
        gcc client.o -o client -lpthread
sever.o:sever.c
        gcc -c sever.c group_chat_system.h
        gcc -c client.c group_chat_system.h
clean:
        rm *.o sever client

四:现象

  

时间: 2024-10-27 23:25:43

Linux多人群聊系统(简单多线程服务器)的相关文章

【LINUX/UNIX网络编程】之简单多线程服务器(多人群聊系统)

RT,Linux下使用c实现的多线程服务器.这个真是简单的不能再简单的了,有写的不好的地方,还希望大神轻拍.(>﹏<) 本学期Linux.unix网络编程的第四个作业. 先上实验要求: [实验目的] 1.熟练掌握线程的创建与终止方法: 2.熟练掌握线程间通信同步方法: 3.应用套接字函数完成多线程服务器,实现服务器与客户端的信息交互. [实验内容] 通过一个服务器实现最多5个客户之间的信息群发. 服务器显示客户的登录与退出: 客户连接后首先发送客户名称,之后发送群聊信息: 客户输入bye代表退

linux小白-基础篇-系统简单优化

作为一个刚刚接触Linux的小白,通过一段时间的学习,将我自己的部分笔记整理后拿出来,请求大家指点:因为是"0"基础学起很多地方了解的都不够深入,希望各位前辈能够指点一下:予人玫瑰,手留余香,谢谢! 因为条件有限环境是用VM搭建起来的,下文主要是根据"老男孩教育视频"中的内容整理出来的系统简单优化,希望各位前辈看过以后可以给出建议: 已学习进步为目的,不喜勿喷!谢谢! 系统简单优化    命令 一.关闭selinux                         

转:Linux下使用Nginx搭建简单图片服务器

最近经常有人问图片上传怎么做,有哪些方案做比较好,也看到过有关于上传图片的做法,但是都不是最好的,今天再这里简单讲一下Nginx实现上传图片以及图片服务器的大致理念. 如果是个人项目或者企业小项目,仅仅只有十来号人使用的小项目,可以使用如下方案: 用户访问系统,使用上传图片功能,那么图片就上传到你的当前项目所在的tomcat服务器上,在/image下,上传成功后用户可以直接访问 http://ip:port/project/images/xxx.jpg 这样做在用户少的时候是没有问题的 当你的企

Linux基础——通过select实现简单的服务器与客户端

在这里,我们还是需要一个管道,只不过,我们只需这一个管道,即可知道,客户端有哪些上线.对话.下线等. 服务器端的实现代码如下: 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <sys/stat.h> 5 #include <sys/types.h> 6 #include <fcntl.h> 7 #include <sys/t

UDP畅聊系统简单版本

带有数据存储的模型图 总体的框架 server中 udp_server.h 其中add_user函数为添加新上线用户信息  1 #pragma once   2 #include <iostream>   3 #include <map>   4 using namespace std;   5 #include "data_pool.h"   6 #include <pthread.h>   7 #include <stdlib.h>

Linux 用libevent实现的简单http服务器

main.c #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <stdlib.h> #include "libev.h" #include <string.h> #include <event2/event.h&

key-value 多线程服务器的Linux C++实现

项目需求 总体思路 网络通信 字符解析 数据存储与查询 1 存储管理 2 数据查询 多线程 待改进 GitHub源码 项目需求 设计一个基于Socket或基于HTTP的服务器,服务内容是提供一种简单的key/value映射关系的管 理与查询 下面的所有操作都是通过结构体Node来传递的: struct Node { char key[KEY_SIZE]; char value[VALUE_SIZE]; }; 本场景中需要client和server两个程序 client端只有两种操作: int A

linux编程实例--简单多进程服务器

主要利用fork事先创建若干个进程,并发处理多个客户端的连接,返回当前系统时间.具体代码如下: server.c # include <sys/types.h> # include <sys/socket.h> # include <netinet/in.h> # include <time.h> # include <string.h> # include <stdio.h> # include <signal.h> #

Linux系统的日志服务器syslogd

系统日志是记录系统中硬件.软件和系统问题的信息,同时还可以监控系统中发生的事件.用户可以通过它来检查错误发生的的原因,或者寻找受到攻击时攻击者留下的痕迹. Windows的事件查看器就是一个日志系统.Linux的日志系统则是通过安装sysklogd这个软件包形成了两个服务: /sbin/klogd 针对硬件(针对内核所产生的,很多和硬件相关) /sbin/syslogd 针对软件(系统的日志服务器) 查看硬件方面的日志: [[email protected] ~]# dmesg |grep -i