综合分析:

基于TCP的聊天室,支持多个用户同时登陆服务器进行聊天。(相当于群)

socket编程,做一对多的通信,必然要用到多线程,保证多个客户端(并行)登陆服务器时同时进行聊天。

项目要求:

利用UDP协议,实现一套聊天室软件。服务器端记录客户端的地址,客户端发送消息后,服务器群发给各个客户端软件。

在写项目前思考一下问题:

● 客户端会不会知道其它客户端地址?

UDP客户端不会直接互连,所以不会获知其它客户端地址,所有客户端地址存储在服务器端。

● 有几种消息类型?

登录:服务器存储新的客户端的地址。把某个客户端登录的消息发给其它客户端。

聊天:服务器只需要把某个客户端的聊天消息转发给所有其它客户端。

退出:服务器删除退出客户端的地址,并把退出消息发送给其它客户端。

● 服务器如何存储客户端的地址?

● 客户端如何同时处理发送和接收?

流程图:

服务器:

客户端:

数据结构可以选择线性数据结构

链表节点结构体:
struct node{struct sockaddr_in addr;struct node *next;
};消息对应的结构体(同一个协议)
typedef struct msg_t
{int type;//L  C  Q  char name[32];//用户名char text[128];//消息正文
}MSG_t;

接下来就是代码:

服务器:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>
#include <pthread.h>
#include "head.h"struct sockaddr_in serveraddr, caddr;//创建有头单向链表
list_t *createList(void);
int login_client(int sockfd,MSG_t msg,list_t *p,struct sockaddr_in caddr);
int chat_client(int sockfd,MSG_t msg,list_t *p,struct sockaddr_in caddr);
int quit_client(int sockfd,MSG_t msg,list_t *p,struct sockaddr_in caddr);void *pthread(void *arg)
{MSG_t msg;int sockfd=(*(int *)arg);msg.type=Chat;strcpy(msg.name,"server");while(1){fgets(msg.text,sizeof(msg.text),stdin);if(msg.text[strlen(msg.text)-1]=='\n')msg.text[strlen(msg.text)-1]='\0';sendto(sockfd,&msg, sizeof(msg), 0,(struct sockaddr *)&serveraddr,sizeof(serveraddr)); }pthread_exit(NULL);
}int main(int argc, char const *argv[])
{if(argc != 2){printf("please input %s <ip> <port>\n",argv[0]);return -1;}//1.创建套接字int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){perror("socket err.");return -1;}//填充服务器端ip和端口serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(atoi(argv[1]));serveraddr.sin_addr.s_addr = inet_addr("0.0.0.0");socklen_t len = sizeof(caddr);//2.绑定if (bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0){perror("bind err.");return -1;}//创建链表list_t *p=createList();//创建线程-服务器端发送消息pthread_t tid;pthread_create(&tid,NULL,pthread,&sockfd);pthread_detach(tid);//循环收发消息MSG_t msg;int recvbyte;while (1){//接收 recvfromrecvbyte = recvfrom(sockfd,&msg, sizeof(msg), 0,(struct sockaddr *)&caddr, &len);if (recvbyte < 0){perror("recvfrom err.");return -1;}switch(msg.type){case Login:login_client(sockfd,msg,p,caddr);break;case Chat: chat_client(sockfd,msg,p,caddr);break;case Quit:quit_client(sockfd,msg,p,caddr);break;}}close(sockfd);return 0;
}//创建有头单向链表
list_t *createList(void)
{//1.创建一个无效头节点:数据域无效,指针域有效list_t *p=(list_t *)malloc(sizeof(list_t));if(NULL == p){perror("malloc head node err.");return NULL;}//2.初始化节点 空链表p->next=NULL;return p;
}//1.客户端登录-服务器工作:
//1》遍历链表,将谁登录的消息发送所有已经登录的用户
//2》将新登录的客户端的ip和端口保存到链表中
int login_client(int sockfd,MSG_t msg,list_t *p,struct sockaddr_in caddr)
{   list_t *pnew=NULL;//1》遍历链表,将谁登录的消息发送所有已经登录的用户sprintf(msg.text,"%s login.",msg.name);while(p->next != NULL){p=p->next;sendto(sockfd,&msg,sizeof(msg),0,\(struct sockaddr *)&(p->caddr),sizeof(p->caddr));}//2》将新登录的客户端的ip和端口保存到链表中//1-创建新节点保存pnew=(list_t *)malloc(sizeof(list_t));if(NULL == pnew){perror("malloc new node err.");return -1;}//2-初始化pnew->caddr=caddr;pnew->next=NULL;//3-将节点连接到链表最后 p保存的链表最后一个节点的地址//直接链接最后就可以p->next=pnew;return 0;
}//2.聊天-服务工作:
//1》将消息发送给所有除自己已经登录的用户
int chat_client(int sockfd,MSG_t msg,list_t *p,struct sockaddr_in caddr)
{//1》将消息发送给所有除自己已经登录的用户//1-遍历链表,只有不是自己的ip和端口就发送消息while(p->next != NULL){p=p->next;if(memcmp(&(p->caddr),&caddr,sizeof(caddr)) != 0){sendto(sockfd,&msg,sizeof(msg),0,\(struct sockaddr *)&(p->caddr),sizeof(p->caddr));}}return 0;
}//3。客户端推出-服务器工作
//1》将推出的用户消息发送给还登录着的用户
//2》从链表中删除推出用户的ip和端口
int quit_client(int sockfd,MSG_t msg,list_t *p,struct sockaddr_in caddr)
{list_t *pdel=NULL;while(p->next != NULL){if(memcmp(&(p->next->caddr),&caddr,sizeof(caddr))==0){pdel=p->next;p->next=pdel->next;free(pdel);pdel=NULL;}else{p=p->next;sendto(sockfd,&msg,sizeof(msg),0,\(struct sockaddr *)&(p->caddr),sizeof(p->caddr));}}return 0;
}

客户端:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>
#include <signal.h>
#include "head.h"int sockfd;
MSG_t msg;
struct sockaddr_in serveraddr;void handler(int sig)
{msg.type=Quit;sendto(sockfd,&msg, sizeof(msg), 0,(struct sockaddr *)&serveraddr,sizeof(serveraddr)); exit(-1);
}int main(int argc, char const *argv[])
{if(argc != 3){printf("please input %s <ip> <port>\n",argv[0]);return -1;}//1.创建套接字sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){perror("socket err.");return -1;}//填充服务器端ip和端口serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(atoi(argv[2]));serveraddr.sin_addr.s_addr = inet_addr(argv[1]);//ctrl + c signal(SIGINT,handler);//循环收发消息int recvbyte;//1.登录msg.type=Login;//从终端获取用户名printf("please input name>>");fgets(msg.name,sizeof(msg.name),stdin);if(msg.name[strlen(msg.name)-1]=='\n')msg.name[strlen(msg.name)-1]='\0';//发送登录消息 sendtosendto(sockfd,&msg, sizeof(msg), 0,(struct sockaddr *)&serveraddr,sizeof(serveraddr)); pid_t pid=fork();if(pid < 0){perror("fork err.");return -1;}else if(pid == 0){//登录成功循环聊天while (1){fgets(msg.text,sizeof(msg.text),stdin);if(msg.text[strlen(msg.text)-1]=='\n')msg.text[strlen(msg.text)-1]='\0';if(strncmp(msg.text,"quit",4) == 0){msg.type=Quit;sendto(sockfd,&msg, sizeof(msg), 0,(struct sockaddr *)&serveraddr,sizeof(serveraddr)); kill(SIGKILL,getppid());exit(-1);}else{msg.type=Chat;}//发送消息 sendtosendto(sockfd,&msg, sizeof(msg), 0,(struct sockaddr *)&serveraddr,sizeof(serveraddr)); }}else{//循环接受while(1){int ret=recvfrom(sockfd,&msg, sizeof(msg), 0,NULL, NULL);if(ret < 0){perror("recvfrom err.");return -1;}printf("%s:%s\n",msg.name,msg.text);}}close(sockfd);return 0;
}

白嫖点赞!!!

基于TCP的网络聊天室相关推荐

  1. 基于TCP的网络聊天室实现(C语言)

    基于TCP的网络聊天室实现(C语言) 一.网络聊天室的功能 二.网络聊天室的结果展示 三.实现思路及流程 四.代码及说明 1.LinkList.h 2.LinkList.c 3.client.c 4. ...

  2. QT学习:基于TCP的网络聊天室程序

    TCP与UDP的差别如图: 一.TCP工作原理 如下图所示,TCP能够为应用程序提供可靠的通信连接,使一台计算机发出的字节流无差错 地送达网络上的其他计算机.因此,对可靠性要求高的数据通信系统往往使用 ...

  3. 【基于UDP的网络聊天室】

    总结下近期写的小项目,在学习中同时积累解决问题的经验,以及真正的项目中解决问题的思路,如有不合理地方,请多指教! 一.项目名称 基于UDP的网络聊天室 二.功能 1.当有新用户登录时,其他在线用户可以 ...

  4. 基于UDP的网络聊天室网络编程0811作业-洪庆乐

    项目:基于UDP的网络聊天室 功能:1.服务器日志系统,且可以查看(实现) 2.有用户,其他用户收到这个人登入信息(实现) 3.群发消息(实现) 4.如果有用户下线,其他用户收到下线消息(实现) 5. ...

  5. 【毕业设计之PHP系列】基于PHP的网络聊天室系统

    基于PHP的网络聊天室系统 摘要:我们生活在一个通信变得非常重要的世界里,人们需要同他人快速容易的进行交流.E-mail.电话.邮件以及在线聊天是以书写文字的形式让人们进行思想交流的媒体.通信时一个重 ...

  6. Linux C/TCP多线程网络聊天室

    多线程TCP网络聊天室 我们都知道TCP是一种基于连接的传输协议,使用多线程来实现其实步骤很简单. 首先说明一下项目:服务端开启后,直接运行客户端可以加入聊天室,同时其他客户端可以接收到某某客户端进入 ...

  7. python基于udp的网络聊天室再用tkinter显示_Python实现网络聊天室的示例代码(支持多人聊天与私聊)...

    实验名称: 网络聊天室 功能: i. 掌握利用Socket进行编程的技术 ii. 掌握多线程技术,保证双方可以同时发送 iii. 建立聊天工具 iv. 可以和单人聊天 v. 可以和多个人同时进行聊天 ...

  8. 【完整代码及文档】基于Java的网络聊天室系统的设计与实现

    摘 要 计算机从出现到现在有了飞速的发展,现阶段的计算机已经不单单是用于进行运算的独立的个体了,跟随计算机一同发展的还有互联网技术,经过了长久的发展,互联网技术有了日新月异的发展,它的发展速度和计算机 ...

  9. javaweb课程设计:基于websocket的网络聊天室(所有的资源和代码还有详细步骤我都会提供)

    1 课程设计目的和任务 本项目的是实现在web应用上进行多人聊天,为以后在大型项目中实现客服在线服务做一个测试,提前了解HTML5新特性,熟练掌握websocket技术. 2 课程设计的主要内容 实现 ...

最新文章

  1. redis bitmap
  2. windows找不到msconfig解决方法
  3. 企业微信的corpsecret在哪里?
  4. LeetCode题组:第543题-二叉树的直径
  5. ace+arm+linux,用NDK编译ACE在Android上运行
  6. c语言奇数正偶数负,C语言二级考试练习题循环控制结构(二)
  7. Docker学习二:Docker镜像与容器
  8. cron每月1号_微信服务号按粉丝标签分组群发消息怎样实现?
  9. 验证码 随机生成器 详解
  10. python bottle部署_如何使用python-Bottle框架创建REST API应用程序,以及如何在apache服务器上部署restapi应用程序?...
  11. java新增mysql时 中文出现_Java项目往数据库中插入数据,出现中文乱码
  12. 教你彻底禁止暴风影音后门进程自己启动
  13. 线性同余法产生1000个随机数
  14. mysql 1698 错误
  15. 案例|工业物联网解决方案•智慧水务云平台
  16. 【AVD】视频解码时如何获取 coded_width coded_height 即参与编码的宽高
  17. 拼多多商家推广常见问题解答!
  18. 第三方登录之微信登录
  19. trigger()方法
  20. C# 如何创建一个Windows服务(Windows Service)

热门文章

  1. 红米 K40 开热点后,笔记本电脑搜索不到热点问题的解决
  2. 大坝安全监测设备(数据采集仪MCU)-守护水库安全防线
  3. 【numpy_financial金融函数-复现复利威力】
  4. 缺失MSVCP120D.dll和MSVCR120D.dll
  5. python爬虫基础
  6. win7台式机光驱计算机里不显示器,Win7系统下我的电脑中没有光驱图标如何解决...
  7. 太极快速开发平台:帮助中心目录
  8. google人工智能
  9. SparkSQL讲解
  10. Python编程练习(三):21 - 30