服务器端的主要功能:

实现多用户群体聊天功能(此程序最多设定为10人,可进行更改),每个人所发送的消息其他用户均可以收到。用户可以随意的加入或退出(推出以字符串“bye”实现),服务器也可以进行关闭。

服务器端的程序结构:

总共有三个函数:主函数(main),实现服务器端的初始化,接受连接;消息处理函数(rcv_snd),接受某一用户的消息,将其进行简单处理之后发送给其他所有的用户;退出函数(quit),可实现服务器关停。

这三个函数分别从属于三个线程(准确说是大于等于三个,下面说明原因):main函数的作为诛仙程线程,又创建了一个退出函数所在的线程,以及每次接受到一个连接之后会新创建一个对此连接的消息进行处理的线程(多于三个的原因在此)。

具体代码实现如下:

  1. #include<time.h>
  2. #include<stdio.h>
  3. #include<sys/socket.h>
  4. #include<netinet/in.h>
  5. #include<string.h>
  6. #define LISTENQ 5
  7. #define MAXLINE 512
  8. #define MAXMEM 10
  9. #define NAMELEN 20
  10. int listenfd,connfd[MAXMEM];//分别记录服务器端的套接字与连接的多个客户端的套接字
  11. void quit();//服务器关闭函数
  12. void rcv_snd(int n);//服务器接收并转发消息函数
  13. int main()
  14. {
  15. pthread_t thread;
  16. struct sockaddr_in servaddr,cliaddr;
  17. socklen_t len;
  18. time_t ticks;
  19. char buff[MAXLINE];
  20. //调用socket函数创建服务器端的套接字
  21. printf("Socket...\n");
  22. listenfd=socket(AF_INET,SOCK_STREAM,0);
  23. if(listenfd<0)
  24. {
  25. printf("Socket created failed.\n");
  26. return -1;
  27. }
  28. //调用bind函数使得服务器端的套接字与地址实现绑定
  29. printf("Bind...\n");
  30. servaddr.sin_family=AF_INET;
  31. servaddr.sin_port=htons(6666);
  32. servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
  33. if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
  34. {
  35. printf("Bind failed.\n");
  36. return -1;
  37. }
  38. //调用listen函数,将一个主动连接套接字变为被动的倾听套接字
  39. //在此过程中完成tcp的三次握手连接
  40. printf("listening...\n");
  41. listen(listenfd,LISTENQ);
  42. //创建一个线程,对服务器程序进行管理(关闭)
  43. pthread_create(&thread,NULL,(void*)(&quit),NULL);
  44. //记录空闲的客户端的套接字描述符(-1为空闲)
  45. int i=0;
  46. for(i=0;i<MAXMEM;i++)
  47. {
  48. connfd[i]=-1;
  49. }
  50. while(1)
  51. {
  52. len=sizeof(cliaddr);
  53. for(i=0;i<MAXMEM;i++)
  54. {
  55. if(connfd[i]==-1)
  56. {
  57. break;
  58. }
  59. }
  60. //调用accept从listen接受的连接队列中取得一个连接
  61. connfd[i]=accept(listenfd,(struct sockaddr*)&cliaddr,&len);
  62. ticks=time(NULL);
  63. sprintf(buff,"% .24s \r \n",ctime(&ticks));
  64. printf("%s Connect from: %s,port %d\n\n",buff,inet_ntoa(cliaddr.sin_addr.s_addr),ntohs(cliaddr.sin_port));
  65. //针对当前套接字创建一个线程,对当前套接字的消息进行处理
  66. pthread_create(malloc(sizeof(pthread_t)),NULL,(void*)(&rcv_snd),(void*)i);
  67. }
  68. return 0;
  69. }
  70. void quit()
  71. {
  72. char msg[10];
  73. while(1)
  74. {
  75. scanf("%s",msg);
  76. if(strcmp("quit",msg)==0)
  77. {
  78. printf("Byebye...\n");
  79. close(listenfd);
  80. exit(0);
  81. }
  82. }
  83. }
  84. void rcv_snd(int n)
  85. {
  86. char* ask="Your name please:";
  87. char buff[MAXLINE];
  88. char buff1[MAXLINE];
  89. char buff2[MAXLINE];
  90. char name[NAMELEN];
  91. time_t ticks;
  92. int i=0;
  93. int retval;
  94. //获取此进程对应的套接字用户的名字
  95. write(connfd[n],ask,strlen(ask));
  96. int len;
  97. len=read(connfd[n],name,NAMELEN);
  98. if(len>0)
  99. {
  100. name[len]=0;
  101. }
  102. //把当前用户的加入告知所有用户
  103. strcpy(buff,name);
  104. strcat(buff,"\tjoin in\0");
  105. for(i=0;i<MAXMEM;i++)
  106. {
  107. if(connfd[i]!=-1)
  108. {
  109. write(connfd[i],buff,strlen(buff));
  110. }
  111. }
  112. //接受当前用户的信息并将其转发给所有的用户
  113. while(1)
  114. {
  115. if((len=read(connfd[n],buff1,MAXLINE))>0)
  116. {
  117. buff1[len]=0;
  118. //当当前用户的输入信息为“bye”时,当前用户退出
  119. if(strcmp("bye",buff)==0)
  120. {
  121. close(connfd[n]);
  122. connfd[n]=-1;
  123. pthread_exit(&retval);
  124. }
  125. ticks=time(NULL);
  126. 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));
  1. strcpy(buff,name);
  2. strcat(buff,"\t");
  3. strcat(buff,buff2);
  4. strcat(buff,buff1);
  5. for(i=0;i<MAXMEM;i++)
  6. {
  7. if(connfd[i]!=-1)
  8. {
  9. write(connfd[i],buff,strlen(buff));
  10. }
  11. }
  12. }
  13. }

Linux C 网络编程——多线程的聊天室实现(服务器端)的更多相关文章

  1. Linux C 网络编程——多线程的聊天室实现(server端)

    server端的主要功能: 实现多用户群体聊天功能(此程序最多设定为10人.可进行更改),每一个人所发送的消息其它用户均能够收到.用户能够任意的增加或退出(推出以字符串"bye"实 ...

  2. 网络编程TCP协议-聊天室

    网络编程TCP协议-聊天室(客户端与服务端的交互); <span style="font-size:18px;">1.客户端发数据到服务端.</span> ...

  3. 使用Android网络编程实现简易聊天室

    在Java中我们可以利用socket编程实现聊天室,在Android中也一样,因为Android完全支持JDK本身的TCP.UDP网络通信API.我们可以使用ServerSocket.Socket来建 ...

  4. 网络编程-基于Websocket聊天室(IM)系统

    目录 一.HTML5 - Websocket协议 二.聊天室(IM)系统的设计 2.1.使用者眼中的聊天系统 2.2.开发者眼中的聊天系统 2.3.IM系统的特性 2.4.心跳机制:解决网络的不确定性 ...

  5. 嵌入式linux的网络编程(1)--TCP/IP协议概述

    嵌入式linux的网络编程(1)--TCP/IP协议概述 1.OSI参考模型及TCP/IP参考模型 通信协议用于协调不同网络设备之间的信息交换,它们建立了设备之间互相识别的信息机制.大家一定都听说过著 ...

  6. Linux C网络编程学习笔记

    Linux C网络编程总结报告 一.Linux C 网络编程知识介绍: 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户端:(client) 在网络程序中, ...

  7. Linux C++ 网络编程学习系列(1)——端口复用实现

    Linux C++ 网络编程学习系列(1)--端口复用实现 源码地址:https://github.com/whuwzp/linuxc/tree/master/portreuse 源码说明: serv ...

  8. Linux&C网络编程————“聊天室”

    从上周到现在一直在完成最后的项目,自己的聊天室,所以博客就没怎么跟了,今天晚上自己的聊天室基本实现,让学长检查了,也有好些bug,自己还算满意,主要实现的功能有: 登录注册 附近的人(服务器端全部在线 ...

  9. Linux&C网络编程————“聊天室”

    从上周到现在一直在完成最后的项目,自己的聊天室,所以博客就没怎么跟了,今天晚上自己的聊天室基本实现,让学长检查了,也有好些bug,自己还算满意,主要实现的功能有: 登录注册 附近的人(服务器端全部在线 ...

随机推荐

  1. ThoughtWorks 面试备忘录

    ThoughtWorks 面试备忘录 前言 前段时间 ThoughtWorks 在网上和拉勾网合作搞了一次网络招聘,名为抛弃简历!让代码说话!,可谓赚足了眼球,很多程序猿纷纷摩拳擦掌.踊跃提交代码,在 ...

  2. 浅谈网络爬虫爬js动态加载网页(一)

    由于别的项目组在做舆情的预言项目,我手头正好没有什么项目,突然心血来潮想研究一下爬虫.分析的简单原型.网上查查这方面的资料还真是多,眼睛都看花了.搜了搜对于我这种新手来说,想做一个简单的爬虫程序,所以 ...

  3. SPOJ130_Rent your airplane and make money_单调队列DP实现

    题意比较简单,状态转移方程也比较容易得出: f[i]=max{ f [ j ] }+p[i],(j的结束时间在i开始时间之前) 若i开始之前没有结束的j,则f[i]=p[i]; 因数据量太大(n< ...

  4. Hibernate注解(二):关联关系映射注解

    关联关系映射注解以下项目均在之前相应代码的基础上进行的修改.这些项目均需要做的是: 删除映射文件 在hibernate.cfg.xml中注册实体类 注解的重要位置在实体类中关联属性上.这里是关联 ...

  5. netty服务端启动--ServerBootstrap源码解析

    netty服务端启动--ServerBootstrap源码解析 前面的第一篇文章中,我以spark中的netty客户端的创建为切入点,分析了netty的客户端引导类Bootstrap的参数设置以及启动 ...

  6. 分享Sql Server 2008 r2 数据备份,同步服务器数据(二.本地发布,订阅)

    上一篇文章中写到了数据库的本地备份,这一篇主要分享一下关于不同服务器的数据备份,主要是使用sql server中的本地发布,本地订阅功能,在数据库的读写分离中,也会经常性的用到这个功能. 复制-> ...

  7. 纯异步nodejs文件夹(目录)复制

    思路: 1.callback 驱动 2.递归所有需要复制文件 3.在一定阀值下并发复制文件 4.运行需要安装 async.js     npm install async 代码如下: var asyn ...

  8. 【分页工具-spring boot】Mybatis PageHelper 集成Spring boot

    官方文档:https://github.com/pagehelper/pagehelper-spring-boot 1.引入包,测试过以下版本兼容性还是比较好的 <!--Mybatis-Spri ...

  9. 跟我学SpringCloud | 第四篇:熔断器Hystrix

    跟我学SpringCloud | 第四篇:熔断器Hystrix 1. 熔断器 服务雪崩 在正常的微服务架构体系下,一个业务很少有只需要调用一个服务就可以返回数据的情况,这种比较常见的是出现在demo中 ...

  10. putty秘钥转换成xhell支持的格式

    使用XShell导入KEY的时候报“Failed to import the user key!”错误 这个错误表明导入的private key文件不是XShell所支持的,有三种可能: 将Publi ...