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[];
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多人群聊系统(简单多线程服务器)的更多相关文章
- 【LINUX/UNIX网络编程】之简单多线程服务器(多人群聊系统)
RT,Linux下使用c实现的多线程服务器.这个真是简单的不能再简单的了,有写的不好的地方,还希望大神轻拍.(>﹏<) 本学期Linux.unix网络编程的第四个作业. 先上实验要求: [ ...
- 【LINUX/UNIX网络编程】之使用消息队列,信号量和命名管道实现的多进程服务器(多人群聊系统)
RT,使用消息队列,信号量和命名管道实现的多人群聊系统. 本学期Linux.unix网络编程的第三个作业. 先上实验要求: 实验三 多进程服务器 [实验目的] 1.熟练掌握进程的创建与终止方法: 2 ...
- Linux 用libevent实现的简单http服务器
Linux 用libevent实现的简单http服务器 main.c #include <stdio.h> #include <sys/types.h> #include &l ...
- Linux 用epoll实现的简单http服务器
Linux 用epoll实现的简单http服务器 main.c #include <stdio.h> #include <sys/types.h> #include <s ...
- 转:Linux下使用Nginx搭建简单图片服务器
最近经常有人问图片上传怎么做,有哪些方案做比较好,也看到过有关于上传图片的做法,但是都不是最好的,今天再这里简单讲一下Nginx实现上传图片以及图片服务器的大致理念. 如果是个人项目或者企业小项目,仅 ...
- 39条常见的Linux系统简单面试题
39条常见的Linux系统简单面试题 本文主要分享39条常见的Linux系统简单面试题,其中包括如何看当前Linux系统有几颗物理CPU和每颗CPU的核数.如何实时查看网卡流量为多少等等,希望对你有所 ...
- Linux系统搭建Red5服务器
Linux系统搭建Red5服务器 Red5 是 支持Windows,Linux等多平台的RTMP流媒体服务器,Windows下搭建相对容易,图形界面操作比较简单,Linux服务器的环境下没有图形界面, ...
- Linux系统编程@多线程编程(一)
多线程编程 涉及操作系统原理概念 时间片 进程状态 上下文: 对进程来说,就是进程的执行环境,具体就是各个变量和数据,包括所有的寄存器变量.打开的文件.内存信息等. 进程的写时复制:由于一般 fork ...
- linux系统下svn服务器操作命令
linux系统下svn服务器操作命令 .输出指定文件或URL的内容. svncat 目标[@版本]…如果指定了版本,将从指定的版本开始查找. svncat -r PREV filename > ...
随机推荐
- [问题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\) 是非 ...
- JSON-SCHEMA
这几天在写代码,和开发那边规范统一后,注释的JOSN需要写清楚schema, 于是学习了一下,国内的东西确实很少,看官网的英文文档也很蛋疼. 就把自己和看到的总结一下: http://json-sch ...
- linux应用程序开发-文件编程-系统调用方式
在看韦东山视频linux驱动方面有一些吃力,究其原因,虽然接触过linux应用程序编程,但是没有深入去理解,相关函数用法不清楚,正好看到国嵌视频对这一方面讲的比较透彻, 所以把学习过程记录下来,也作为 ...
- Mac下安装Wireshark,双击闪退
Mac OS X上使用Wireshark抓包(http://blog.csdn.net/phunxm/article/details/38590561) Mac下安装Wireshark /Appli ...
- STM32学习笔记(九) 外部中断,待机模式和事件唤醒
学会知识只需要不段的积累和提高,但是如何将知识系统的讲解出来就需要深入的认知和系统的了解.外部中断和事件学习难度并不高,不过涉及到STM32的电源控制部分,还是值得认真了解的,在本文中我将以实际代码为 ...
- javascript事件之:谈谈自定义事件
对于JavaScript自定义事件,印象最深刻的是用jQuery在做图片懒加载的时候.给需要懒加载的图片定义一个appear事件.当页面图片开始出现时候,触发这个自定义的appear事件(注意,这里只 ...
- 0020 Linux 文件操作命令
1. 创建文件 touch 文件名 2. 删除文件 rm 文件名 3. 复制文件 cp 源文件 目录 4.剪切文件 mv 源文件 目标文件 5.重命名文件 mv 源文件名 新文件名 6.改变文件权限 ...
- archaism remains
Time past cannot be called back again. 时间不能倒流. Time tries all. 路遥知马力,日久见人心. Tit for tat is fair p ...
- .NET 4.5 WPF Ribbon
文/嶽永鹏 Visual Studio 2012 DO.NET 4.5 Ribbon 界面编程. 代码 =============================================== ...
- SAP模块常用增强总结{转载}
MM模块: 采购订单增强: BADI :ME_GUI_PO_CUST ME_PROCESS_PO_CUST 物料凭证增强: BADI:MB_DOCUMENT_BADI USER-EXIT:MBCF00 ...