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,自己还算满意,主要实现的功能有: 登录注册 附近的人(服务器端全部在线 ...
随机推荐
- qtextedit中的光标问题(通过调用repaint去掉Focus的阴影)
[问题]两个textedit,取名为view0,view1.实现view0输入固定的字符个数后,用setFocus切换聚焦到view1,但是切换完了之后view0还会保留光标残影,出现两个文本框中都有 ...
- 任何一件事,如果你不投入时间和精力去驯养,就不可能产生真正的兴趣和热爱(Focus Feedback FixIt的原理) good
这两本书和我们说的兴趣结合起来,为我们指明了精进的道路: 选择一个你感兴趣的方向 刻意练习 持续投入时间和精力 所谓刻意练习,简单说就是“3F”,即: Focus Feedback Fix it Fo ...
- .NET Core RC2在Linux下部署
前言 目前ASP.NET Core RC2已经正式发布了,可以参考如下链接: https://blogs.msdn.microsoft.com/dotnet/2016/05/06/net-core-r ...
- Spring特点
1.非侵入式所谓非侵入式是指,Spring框架的API不会在业务逻辑上出现,即业务逻辑是POJO(Plain Old Java Objects).由于业务逻辑中没有Spring的API,所以业务逻辑可 ...
- kafka 0.11.0.3 源码编译
首先下载 kafka 0.11.0.3 版本 源码: http://mirrors.hust.edu.cn/apache/kafka/0.11.0.3/ 下载源码 首先安装 gradle,不再说明 1 ...
- Scala 学习之路(六)—— 常用集合类型之 List & Set
一.List字面量 List是Scala中非常重要的一个数据结构,其与Array(数组)非常类似,但是List是不可变的,和Java中的List一样,其底层实现是链表. scala> val l ...
- spring 5.x 系列第14篇 —— 整合RabbitMQ (代码配置方式)
源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.说明 1.1 项目结构说明 本用例关于rabbitmq的整合提供简单消 ...
- appcan 多按钮提示框
使用 appcan.window.alert EG: var btnList=new Array(); btnList[0]="确认"; btnList[1]="取消& ...
- Xshell连接WSL
Xshell连接WSL Windows的Windows Subsystem for Linux很好用, 可以直接使用Linux的CLI模式, 对于开发来说很友好. 安装 Windows 10系统上, ...
- oh-my-zsh自定义配置
oh-my-zsh主题配置 默认的zsh主题robbyrussell已经很棒了, 简洁高效, 能很好的显示git的相关信息, 比如branch信息, 修改, 删除, 添加等操作. 但是多用户的话就不能 ...