Linux C 网络编程——多线程的聊天室实现(服务器端)
服务器端的主要功能:
实现多用户群体聊天功能(此程序最多设定为10人,可进行更改),每个人所发送的消息其他用户均可以收到。用户可以随意的加入或退出(推出以字符串“bye”实现),服务器也可以进行关闭。
服务器端的程序结构:
总共有三个函数:主函数(main),实现服务器端的初始化,接受连接;消息处理函数(rcv_snd),接受某一用户的消息,将其进行简单处理之后发送给其他所有的用户;退出函数(quit),可实现服务器关停。
这三个函数分别从属于三个线程(准确说是大于等于三个,下面说明原因):main函数的作为诛仙程线程,又创建了一个退出函数所在的线程,以及每次接受到一个连接之后会新创建一个对此连接的消息进行处理的线程(多于三个的原因在此)。
具体代码实现如下:
- #include<time.h>
- #include<stdio.h>
- #include<sys/socket.h>
- #include<netinet/in.h>
- #include<string.h>
- #define LISTENQ 5
- #define MAXLINE 512
- #define MAXMEM 10
- #define NAMELEN 20
- int listenfd,connfd[MAXMEM];//分别记录服务器端的套接字与连接的多个客户端的套接字
- void quit();//服务器关闭函数
- void rcv_snd(int n);//服务器接收并转发消息函数
- int main()
- {
- pthread_t thread;
- struct sockaddr_in servaddr,cliaddr;
- socklen_t len;
- time_t ticks;
- char buff[MAXLINE];
- //调用socket函数创建服务器端的套接字
- printf("Socket...\n");
- listenfd=socket(AF_INET,SOCK_STREAM,0);
- if(listenfd<0)
- {
- printf("Socket created failed.\n");
- return -1;
- }
- //调用bind函数使得服务器端的套接字与地址实现绑定
- printf("Bind...\n");
- servaddr.sin_family=AF_INET;
- servaddr.sin_port=htons(6666);
- servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
- if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
- {
- printf("Bind failed.\n");
- return -1;
- }
- //调用listen函数,将一个主动连接套接字变为被动的倾听套接字
- //在此过程中完成tcp的三次握手连接
- printf("listening...\n");
- listen(listenfd,LISTENQ);
- //创建一个线程,对服务器程序进行管理(关闭)
- pthread_create(&thread,NULL,(void*)(&quit),NULL);
- //记录空闲的客户端的套接字描述符(-1为空闲)
- int i=0;
- for(i=0;i<MAXMEM;i++)
- {
- connfd[i]=-1;
- }
- while(1)
- {
- len=sizeof(cliaddr);
- for(i=0;i<MAXMEM;i++)
- {
- if(connfd[i]==-1)
- {
- break;
- }
- }
- //调用accept从listen接受的连接队列中取得一个连接
- connfd[i]=accept(listenfd,(struct sockaddr*)&cliaddr,&len);
- ticks=time(NULL);
- sprintf(buff,"% .24s \r \n",ctime(&ticks));
- printf("%s Connect from: %s,port %d\n\n",buff,inet_ntoa(cliaddr.sin_addr.s_addr),ntohs(cliaddr.sin_port));
- //针对当前套接字创建一个线程,对当前套接字的消息进行处理
- pthread_create(malloc(sizeof(pthread_t)),NULL,(void*)(&rcv_snd),(void*)i);
- }
- return 0;
- }
- void quit()
- {
- char msg[10];
- while(1)
- {
- scanf("%s",msg);
- if(strcmp("quit",msg)==0)
- {
- printf("Byebye...\n");
- close(listenfd);
- exit(0);
- }
- }
- }
- void rcv_snd(int n)
- {
- char* ask="Your name please:";
- char buff[MAXLINE];
- char buff1[MAXLINE];
- char buff2[MAXLINE];
- char name[NAMELEN];
- time_t ticks;
- int i=0;
- int retval;
- //获取此进程对应的套接字用户的名字
- write(connfd[n],ask,strlen(ask));
- int len;
- len=read(connfd[n],name,NAMELEN);
- if(len>0)
- {
- name[len]=0;
- }
- //把当前用户的加入告知所有用户
- strcpy(buff,name);
- strcat(buff,"\tjoin in\0");
- for(i=0;i<MAXMEM;i++)
- {
- if(connfd[i]!=-1)
- {
- write(connfd[i],buff,strlen(buff));
- }
- }
- //接受当前用户的信息并将其转发给所有的用户
- while(1)
- {
- if((len=read(connfd[n],buff1,MAXLINE))>0)
- {
- buff1[len]=0;
- //当当前用户的输入信息为“bye”时,当前用户退出
- if(strcmp("bye",buff)==0)
- {
- close(connfd[n]);
- connfd[n]=-1;
- pthread_exit(&retval);
- }
- ticks=time(NULL);
- sprintf(buff2,"%.24s\r\n",ctime(&ticks));
#include<time.h>
#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#define LISTENQ 5
#define MAXLINE 512
#define MAXMEM 10
#define NAMELEN 20
int listenfd,connfd[MAXMEM];//分别记录服务器端的套接字与连接的多个客户端的套接字
void quit();//服务器关闭函数
void rcv_snd(int n);//服务器接收并转发消息函数
int main()
{
pthread_t thread;
struct sockaddr_in servaddr,cliaddr;
socklen_t len;
time_t ticks;
char buff[MAXLINE];
//调用socket函数创建服务器端的套接字
printf("Socket...\n");
listenfd=socket(AF_INET,SOCK_STREAM,0);
if(listenfd<0)
{
printf("Socket created failed.\n");
return -1;
}
//调用bind函数使得服务器端的套接字与地址实现绑定
printf("Bind...\n");
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(6666);
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
{
printf("Bind failed.\n");
return -1;
}
//调用listen函数,将一个主动连接套接字变为被动的倾听套接字
//在此过程中完成tcp的三次握手连接
printf("listening...\n");
listen(listenfd,LISTENQ);
//创建一个线程,对服务器程序进行管理(关闭)
pthread_create(&thread,NULL,(void*)(&quit),NULL);
//记录空闲的客户端的套接字描述符(-1为空闲)
int i=0;
for(i=0;i<MAXMEM;i++)
{
connfd[i]=-1;
}
while(1)
{
len=sizeof(cliaddr);
for(i=0;i<MAXMEM;i++)
{
if(connfd[i]==-1)
{
break;
}
}
//调用accept从listen接受的连接队列中取得一个连接
connfd[i]=accept(listenfd,(struct sockaddr*)&cliaddr,&len);
ticks=time(NULL);
sprintf(buff,"% .24s \r \n",ctime(&ticks));
printf("%s Connect from: %s,port %d\n\n",buff,inet_ntoa(cliaddr.sin_addr.s_addr),ntohs(cliaddr.sin_port));
//针对当前套接字创建一个线程,对当前套接字的消息进行处理
pthread_create(malloc(sizeof(pthread_t)),NULL,(void*)(&rcv_snd),(void*)i);
}
return 0;
}
void quit()
{
char msg[10];
while(1)
{
scanf("%s",msg);
if(strcmp("quit",msg)==0)
{
printf("Byebye...\n");
close(listenfd);
exit(0);
}
}
}
void rcv_snd(int n)
{
char* ask="Your name please:";
char buff[MAXLINE];
char buff1[MAXLINE];
char buff2[MAXLINE];
char name[NAMELEN];
time_t ticks;
int i=0;
int retval;
//获取此进程对应的套接字用户的名字
write(connfd[n],ask,strlen(ask));
int len;
len=read(connfd[n],name,NAMELEN);
if(len>0)
{
name[len]=0;
}
//把当前用户的加入告知所有用户
strcpy(buff,name);
strcat(buff,"\tjoin in\0");
for(i=0;i<MAXMEM;i++)
{
if(connfd[i]!=-1)
{
write(connfd[i],buff,strlen(buff));
}
}
//接受当前用户的信息并将其转发给所有的用户
while(1)
{
if((len=read(connfd[n],buff1,MAXLINE))>0)
{
buff1[len]=0;
//当当前用户的输入信息为“bye”时,当前用户退出
if(strcmp("bye",buff)==0)
{
close(connfd[n]);
connfd[n]=-1;
pthread_exit(&retval);
}
ticks=time(NULL);
sprintf(buff2,"%.24s\r\n",ctime(&ticks));
- strcpy(buff,name);
- strcat(buff,"\t");
- strcat(buff,buff2);
- strcat(buff,buff1);
- for(i=0;i<MAXMEM;i++)
- {
- if(connfd[i]!=-1)
- {
- write(connfd[i],buff,strlen(buff));
- }
- }
- }
- }
Linux C 网络编程——多线程的聊天室实现(服务器端)的更多相关文章
- Linux C 网络编程——多线程的聊天室实现(server端)
server端的主要功能: 实现多用户群体聊天功能(此程序最多设定为10人.可进行更改),每一个人所发送的消息其它用户均能够收到.用户能够任意的增加或退出(推出以字符串"bye"实 ...
- 网络编程TCP协议-聊天室
网络编程TCP协议-聊天室(客户端与服务端的交互); <span style="font-size:18px;">1.客户端发数据到服务端.</span> ...
- 使用Android网络编程实现简易聊天室
在Java中我们可以利用socket编程实现聊天室,在Android中也一样,因为Android完全支持JDK本身的TCP.UDP网络通信API.我们可以使用ServerSocket.Socket来建 ...
- 网络编程-基于Websocket聊天室(IM)系统
目录 一.HTML5 - Websocket协议 二.聊天室(IM)系统的设计 2.1.使用者眼中的聊天系统 2.2.开发者眼中的聊天系统 2.3.IM系统的特性 2.4.心跳机制:解决网络的不确定性 ...
- 嵌入式linux的网络编程(1)--TCP/IP协议概述
嵌入式linux的网络编程(1)--TCP/IP协议概述 1.OSI参考模型及TCP/IP参考模型 通信协议用于协调不同网络设备之间的信息交换,它们建立了设备之间互相识别的信息机制.大家一定都听说过著 ...
- Linux C网络编程学习笔记
Linux C网络编程总结报告 一.Linux C 网络编程知识介绍: 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户端:(client) 在网络程序中, ...
- Linux C++ 网络编程学习系列(1)——端口复用实现
Linux C++ 网络编程学习系列(1)--端口复用实现 源码地址:https://github.com/whuwzp/linuxc/tree/master/portreuse 源码说明: serv ...
- Linux&C网络编程————“聊天室”
从上周到现在一直在完成最后的项目,自己的聊天室,所以博客就没怎么跟了,今天晚上自己的聊天室基本实现,让学长检查了,也有好些bug,自己还算满意,主要实现的功能有: 登录注册 附近的人(服务器端全部在线 ...
- Linux&C网络编程————“聊天室”
从上周到现在一直在完成最后的项目,自己的聊天室,所以博客就没怎么跟了,今天晚上自己的聊天室基本实现,让学长检查了,也有好些bug,自己还算满意,主要实现的功能有: 登录注册 附近的人(服务器端全部在线 ...
随机推荐
- 3020配置_Java_win10
1. 安装Java SE平台 1° 下载 https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-213315 ...
- 基于maven的项目脚手架,一键创建项目的项目模板
制作基于maven的项目脚手架 Springboot的出现极大的简化了项目开发的配置,然而,到真实使用的时候还是会有一堆配置需要设定.比如依赖管理,各种插件,质量扫描配置,docker配置,持续集成配 ...
- sql server编写简洁四则运算表达式脚本实现计算批次功能(C#等其它编程语言也能直接用此通用表达式)
问题: 在数据库编程开发中,有时会遇到数据量比较大的情况,如果直接大批量进行添加数据.修改数据.删除数据,就会是比较大的事务,事务日志也比较大,耗时久的话会对正常操作造成一定的阻塞.虽不至于达到删库跑 ...
- Python自学day-10
一.多进程 程序中, 大量的计算占用CPU资源,而IO操作不占CPU资源.当程序需要进行大量计算时,Python采用多线程运行的速度不一定比单线程快多少.但是当程序是IO密集型的,那就应该使用多线程来 ...
- SSM(四)Mybatis延迟加载
1.概念 MyBatis中的延迟加载,也称为懒加载,是指在进行关联查询时,按照设置延迟加载规则推迟对关联对象的select查询.延迟加载可以有效的减少数据库压力. 2.关联对象的加载时机 ①.直接加载 ...
- 精通并发与 Netty (二)常用的 rpc 框架
Google Protobuf 使用方式分析 对于 RPC 协议来说,最重要的就是对象的发送与接收,这就要用到序列化与反序列化,也称为编码和解码,序列化与反序列化和网络传输一般都在对应的 RPC 框架 ...
- RT-Thread定时器以及结构体指针的一些思考
定时器分为软件定时器和硬件定时器.顾名思义,软件定时器就是有操作系统提供的软件定时器,硬件定时器就是用硬件芯片提供的定时器. 而在RT-Thread操作系统提供的定时器是软件定时器,但是为了便于管理, ...
- websocket实现群聊和单聊(转)
昨日内容回顾 1.Flask路由 1.endpoint="user" # 反向url地址 2.url_address = url_for("user") 3.m ...
- 设计模式:代理模式是什么,Spring AOP还和它有关系?
接着学习设计模式系列,今天讲解的是代理模式. 定义 什么是代理模式? 代理模式,也叫委托模式,其定义是给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用.它包含了三个角色: Subject: ...
- Web前端——JavaScript扩展补充
JS补充 document也是windows的一个子对象 a标签点击事件 要想设置点击a标签,执行某种方法,推荐在a标签的herf属性使用JavaScript伪协议,实现点击之后执行的js方法,而不是 ...