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,自己还算满意,主要实现的功能有: 登录注册 附近的人(服务器端全部在线 ...
随机推荐
- ASP.NET Core 通过 Microsoft.DotNet.Watcher.Tools 实现热部署
之前开发前端的时候,webpack 会有热更新工具,在修改了代码之后,自动将代码编译,实时展现到页面上,给开发带来了极大的方便. Java也可以通过第三方插件JRebel实现热部署,不用频繁的重启To ...
- 《CSS 设计指南》笔记(Ⅰ)
在图书馆借了这本书,讲的非常好,条理清晰,深入浅出,真的有一种和作者交流的感觉,解决了自己很多困惑,于是决定针对一些平时并不常用但是感觉会用到的知识点做一些笔记,加深印象. 一. 块级元素盒子会扩展到 ...
- screen命令使用简单说明
首先用screen [-S]命令建立一个session,然后就可以在这个session中建立多个window了.使用screen [-S]可以建立多个session,而每个session又可以建立多个 ...
- Nginx+Keepalived部署流程
环境介绍 1)LB01 Hostname:lb01.example.com VIP:192.168.3.33(eth0:0) IP:192.168.3.31(eth0) OS:Centos 7 2)L ...
- Spark学习之路(十二)—— Spark SQL JOIN操作
一. 数据准备 本文主要介绍Spark SQL的多表连接,需要预先准备测试数据.分别创建员工和部门的Datafame,并注册为临时视图,代码如下: val spark = SparkSession.b ...
- spring 5.x 系列第9篇 —— 整合mongodb (xml配置方式)
源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.说明 1.1 项目结构说明 配置文件位于resources下,项目以单 ...
- 针对Linux 文件完整性监控的实现
针对Linux 文件完整性监控的实现 摘要 计算机和互联网是20世纪以来最伟大的发明之一,随着计算机技术的不断发展,人们的生活方式发生了巨大的变化.计算机和互联网的发展给人们的生产生活带来了极大的便利 ...
- 跟我学SpringCloud | 第六篇:Spring Cloud Config Github配置中心
SpringCloud系列教程 | 第六篇:Spring Cloud Config Github配置中心 Springboot: 2.1.6.RELEASE SpringCloud: Greenwic ...
- C# 位运算及实例计算
前言: 平时在实际工作中很少用到这个,虽然都是一些比较基础的东西,但一旦遇到了,又不知所云.刚好最近接触了一些相关这方面的项目,所以也算是对 这些内容重新温习实践了一遍.所以这篇不仅作为个人备忘,也分 ...
- Appium+python自动化(十五)- Android 这些基础知识,你知多少???(超详解)
简介 前边具体操作和实战已经讲解和分享了很多了,但是一些android的一些基础知识,你又知道多少了,你都掌握了吗?这篇就由宏哥给小伙伴们既是一个分享,又是对前边的一次总结.为什么要对这些做一个简单的 ...