一:要求

  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[];
char buf[MSGLEN];
}; struct CLIENTS {
int sockfd;
int port;
char user[];
struct sockaddr_in client;
int stat;
};
struct CLIENTS ent[]; #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[]; 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[];
int port,clientlen;
unsigned char i,index;
struct CLIENTMSG clientMSG;
pthread_t tid;
int *arg; for(i=; i<; i++) {
ent[i].stat = ;
} /***************创建服务器sockfd************/
if((sever_fd = socket(AF_INET, SOCK_STREAM, )) == -) {
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)) == -) {
perror("bind error");
exit(errno);
} /******************listen***********************/
if(listen(sever_fd, ) == -) {
perror("listen error");
exit(errno);
} while() {
clientlen = sizeof(client);
if((client_fd = accept(sever_fd, (struct sockaddr*)&client, &clientlen)) == -) {
perror("accept error");
exit(errno);
}
printf("accept ok\n");
index = ;
for(i=; i<; i++) {
if(ent[i].stat ==){
index = i;
break;
}
} if(index <= ) {
printf("client_fd : %d\n", client_fd);
ent[index].sockfd = client_fd;
ent[index].port = port;
ent[index].client = client;
ent[index].stat = ;
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), );
close(client_fd);
} }
close(sever_fd);
return ;
} 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), ); while() {
bzero(&sendMSG, sizeof(sendMSG));
bzero(&recvMSG, sizeof(recvMSG)); len = recv(ent[index].sockfd, &recvMSG, sizeof(recvMSG), );
if(len == ) {
sendMSG.op = EXIT;
for(i=; i<; i++) {
if(ent[i].stat == )
send(ent[i].sockfd, &sendMSG, sizeof(sendMSG), );
}
}
if(len > ) {
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=; i<; i++) {
if(ent[i].stat == )
send(ent[i].sockfd, &sendMSG, sizeof(sendMSG), );
}
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=; i<; i++) {
//printf("\n%d: %s\n", sendMSG.op, sendMSG.user);
if(ent[i].stat == ) {
if(strncmp(ent[i].user, sendMSG.user, strlen(sendMSG.user)))
send(ent[i].sockfd, &sendMSG, sizeof(sendMSG), );
} }
}
} }

    

  客户端:

#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[];
unsigned int port,len;
struct CLIENTMSG sendMSG;
pthread_t tid; if((sockfd = socket(AF_INET, SOCK_STREAM, )) == -) {
perror("socket error");
exit();
} 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)) == -) {
perror("connect error");
exit(errno);
} len = recv(sockfd, &sendMSG, sizeof(sendMSG), );
if(len > ){
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), );
arg = (struct client_arg*)malloc(sizeof(struct client_arg));
arg->sockfd = sockfd;
pthread_create(&tid, NULL, func, (void*)arg); while() {
// 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", )) {
sendMSG.op = EXIT;
send(sockfd, &sendMSG, sizeof(sendMSG), );
break;
}
send(sockfd, &sendMSG, sizeof(sendMSG), );
}
}
pthread_cancel(tid);
}
close(sockfd);
return ;
} 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() {
bzero(&clientMSG, sizeof(clientMSG));
len = recv(sockfd, &clientMSG, sizeof(clientMSG), );
if(len > ) {
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

四:现象

  

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

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

    RT,Linux下使用c实现的多线程服务器.这个真是简单的不能再简单的了,有写的不好的地方,还希望大神轻拍.(>﹏<) 本学期Linux.unix网络编程的第四个作业. 先上实验要求: [ ...

  2. 【LINUX/UNIX网络编程】之使用消息队列,信号量和命名管道实现的多进程服务器(多人群聊系统)

    RT,使用消息队列,信号量和命名管道实现的多人群聊系统. 本学期Linux.unix网络编程的第三个作业. 先上实验要求: 实验三  多进程服务器 [实验目的] 1.熟练掌握进程的创建与终止方法: 2 ...

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

    Linux 用libevent实现的简单http服务器 main.c #include <stdio.h> #include <sys/types.h> #include &l ...

  4. Linux 用epoll实现的简单http服务器

    Linux 用epoll实现的简单http服务器 main.c #include <stdio.h> #include <sys/types.h> #include <s ...

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

    最近经常有人问图片上传怎么做,有哪些方案做比较好,也看到过有关于上传图片的做法,但是都不是最好的,今天再这里简单讲一下Nginx实现上传图片以及图片服务器的大致理念. 如果是个人项目或者企业小项目,仅 ...

  6. 39条常见的Linux系统简单面试题

    39条常见的Linux系统简单面试题 本文主要分享39条常见的Linux系统简单面试题,其中包括如何看当前Linux系统有几颗物理CPU和每颗CPU的核数.如何实时查看网卡流量为多少等等,希望对你有所 ...

  7. Linux系统搭建Red5服务器

    Linux系统搭建Red5服务器 Red5 是 支持Windows,Linux等多平台的RTMP流媒体服务器,Windows下搭建相对容易,图形界面操作比较简单,Linux服务器的环境下没有图形界面, ...

  8. Linux系统编程@多线程编程(一)

    多线程编程 涉及操作系统原理概念 时间片 进程状态 上下文: 对进程来说,就是进程的执行环境,具体就是各个变量和数据,包括所有的寄存器变量.打开的文件.内存信息等. 进程的写时复制:由于一般 fork ...

  9. linux系统下svn服务器操作命令

    linux系统下svn服务器操作命令 .输出指定文件或URL的内容.  svncat 目标[@版本]…如果指定了版本,将从指定的版本开始查找. svncat -r PREV filename > ...

随机推荐

  1. [问题2014A10] 解答

    [问题2014A10]  解答 考虑如下变形: \[(I_n-A)^2=(AA'-A)(I_n-A)=A(A'-I_n)(I_n-A)=-A(I_n-A)'(I_n-A).\] 因为 \(A\) 是非 ...

  2. JSON-SCHEMA

    这几天在写代码,和开发那边规范统一后,注释的JOSN需要写清楚schema, 于是学习了一下,国内的东西确实很少,看官网的英文文档也很蛋疼. 就把自己和看到的总结一下: http://json-sch ...

  3. linux应用程序开发-文件编程-系统调用方式

    在看韦东山视频linux驱动方面有一些吃力,究其原因,虽然接触过linux应用程序编程,但是没有深入去理解,相关函数用法不清楚,正好看到国嵌视频对这一方面讲的比较透彻, 所以把学习过程记录下来,也作为 ...

  4. Mac下安装Wireshark,双击闪退

     Mac OS X上使用Wireshark抓包(http://blog.csdn.net/phunxm/article/details/38590561) Mac下安装Wireshark /Appli ...

  5. STM32学习笔记(九) 外部中断,待机模式和事件唤醒

    学会知识只需要不段的积累和提高,但是如何将知识系统的讲解出来就需要深入的认知和系统的了解.外部中断和事件学习难度并不高,不过涉及到STM32的电源控制部分,还是值得认真了解的,在本文中我将以实际代码为 ...

  6. javascript事件之:谈谈自定义事件

    对于JavaScript自定义事件,印象最深刻的是用jQuery在做图片懒加载的时候.给需要懒加载的图片定义一个appear事件.当页面图片开始出现时候,触发这个自定义的appear事件(注意,这里只 ...

  7. 0020 Linux 文件操作命令

    1. 创建文件 touch 文件名 2. 删除文件 rm 文件名 3. 复制文件 cp 源文件 目录 4.剪切文件 mv 源文件 目标文件 5.重命名文件 mv 源文件名 新文件名 6.改变文件权限 ...

  8. archaism remains

    Time past cannot be called back again.  时间不能倒流. Time tries all.  路遥知马力,日久见人心.  Tit for tat is fair p ...

  9. .NET 4.5 WPF Ribbon

    文/嶽永鹏 Visual Studio 2012  DO.NET 4.5 Ribbon 界面编程. 代码 =============================================== ...

  10. SAP模块常用增强总结{转载}

    MM模块: 采购订单增强: BADI :ME_GUI_PO_CUST ME_PROCESS_PO_CUST 物料凭证增强: BADI:MB_DOCUMENT_BADI USER-EXIT:MBCF00 ...