• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C语言 > socket多人聊天程序C语言版(二)

socket多人聊天程序C语言版(二)

作者:_acme_ 字体:[增加 减小] 来源:互联网 时间:2017-05-28

_acme_ 通过本文主要向大家介绍了c语言socket编程,c语言socket,c语言socket通信,c语言socket函数,c语言socket网络编程等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

socket多人聊天程序C语言版(一)地址: http://www.weikejianghu.com/article/94938.htm

1V1实现了,1V多也就容易了。不过相对于1V1的程序,我经过大改,采用链表来动态管理。这样效率真的提升不少,至少CPU使用率稳稳的在20以下,不会飙到100了。用C语言写这个还是挺费时间的,因为什么功能函数都要自己写,不像C++有STL库可以用,MFC写就更简单了,接下来我还会更新MFC版本的多人聊天程序。好了,废话少说,进入主题。

这个程序要解决的问题如下:

1.CPU使用率飙升问题 –>用链表动态管理

2.用户自定义聊天,就是想跟谁聊跟谁聊 –> _Client结构体中新增一个ChatName字段,用来表示要和谁聊天,这个字段很重要,因为server转发消息的时候就是按照这个字段来转发的。

3.中途换人聊天,就是聊着聊着,想和别人聊,而且自己还一样能接收到其它人发的消息 –> 这个就要小改客户端的代码了,可以在发送聊天消息之前插入一段代码,用来切换聊天用户。具体做法就是,用getch()函数读取ESC键,如果用户按了这个键,则表示想切换用户,然后会输出一行提示,请输入chat name,就是想要和谁聊天的名字,发送这个名字过去之前要加一个标识符,表示这个消息是切换聊天用户消息。然后server接收到这个消息后会判断第一个字符是不是标识符,第二个字符不能是标识符,则根据这个name来查找当前在线的用户,然后修改想切换聊天用户的ChatName为name这个用户。(可能有点绕,不懂的看代码就清晰易懂了~)

4.下线后提醒对方 –> 还是老套路,只要send对方不通就当对方下线了。

编写环境:WIN10,VS2015

效果图:

为了方便就不用虚拟机演示了,但是在虚拟机是肯定可以的,应该说只要是局域网,能互相ping通就可以使用这个程序。

Server code:

链表头文件:

#ifndef _CLIENT_LINK_LIST_H_
#define _CLIENT_LINK_LIST_H_

#include <WinSock2.h>

#include <stdio.h>

//客户端信息结构体
typedef struct _Client
{
 SOCKET sClient;   //客户端套接字
 char buf[128];   //数据缓冲区
 char userName[16];  //客户端用户名
 char IP[20];   //客户端IP
 unsigned short Port; //客户端端口
 UINT_PTR flag;   //标记客户端,用来区分不同的客户端
 char ChatName[16];  //指定要和哪个客户端聊天
 _Client* next;   //指向下一个结点
}Client, *pClient;

/* * function 初始化链表 * return 无返回值 */
void Init();

/* * function 获取头节点 * return 返回头节点 */
pClient GetHeadNode();

/* * function 添加一个客户端 * param client表示一个客户端对象 * return 无返回值 */
void AddClient(pClient client);

/* * function 删除一个客户端 * param flag标识一个客户端对象 * return 返回true表示删除成功,false表示失败 */
bool RemoveClient(UINT_PTR flag);

/* * function 根据name查找指定客户端 * param name是指定客户端的用户名 * return 返回一个client表示查找成功,返回INVALID_SOCKET表示无此用户 */
SOCKET FindClient(char* name);

/* * function 根据SOCKET查找指定客户端 * param client是指定客户端的套接字 * return 返回一个pClient表示查找成功,返回NULL表示无此用户 */
pClient FindClient(SOCKET client);

/* * function 计算客户端连接数 * param client表示一个客户端对象 * return 返回连接数 */
int CountCon();

/* * function 清空链表 * return 无返回值 */
void ClearClient();

/* * function 检查连接状态并关闭一个连接 * return 返回值 */
void CheckConnection();

/* * function 指定发送给哪个客户端 * param FromName,发信人 * param ToName, 收信人 * param data, 发送的消息 */
void SendData(char* FromName, char* ToName, char* data);


#endif //_CLIENT_LINK_LIST_H_

</div>

链表cpp文件:

#include "ClientLinkList.h"

pClient head = (pClient)malloc(sizeof(_Client)); //创建一个头结点

/* * function 初始化链表 * return 无返回值 */
void Init()
{
 head->next = NULL;
}

/* * function 获取头节点 * return 返回头节点 */
pClient GetHeadNode()
{
 return head;
}

/* * function 添加一个客户端 * param client表示一个客户端对象 * return 无返回值 */
void AddClient(pClient client)
{
 client->next = head->next; //比如:head->1->2,然后添加一个3进来后是
 head->next = client;  //3->1->2,head->3->1->2
}

/* * function 删除一个客户端 * param flag标识一个客户端对象 * return 返回true表示删除成功,false表示失败 */
bool RemoveClient(UINT_PTR flag)
{
 //从头遍历,一个个比较
 pClient pCur = head->next;//pCur指向第一个结点
 pClient pPre = head;  //pPre指向head 
 while (pCur)
 {
  // head->1->2->3->4,要删除2,则直接让1->3
  if (pCur->flag == flag)
  {
   pPre->next = pCur->next;
   closesocket(pCur->sClient); //关闭套接字
   free(pCur); //释放该结点
   return true;
  }
  pPre = pCur;
  pCur = pCur->next;
 }
 return false;
}

/* * function 查找指定客户端 * param name是指定客户端的用户名 * return 返回socket表示查找成功,返回INVALID_SOCKET表示无此用户 */
SOCKET FindClient(char* name)
{
 //从头遍历,一个个比较
 pClient pCur = head;
 while (pCur = pCur->next)
 {
  if (strcmp(pCur->userName, name) == 0)
   return pCur->sClient;
 }
 return INVALID_SOCKET;
}

/* * function 根据SOCKET查找指定客户端 * param client是指定客户端的套接字 * return 返回一个pClient表示查找成功,返回NULL表示无此用户 */
pClient FindClient(SOCKET client)
{
 //从头遍历,一个个比较
 pClient pCur = head;
 while (pCur = pCur->next)
 {
  if (pCur->sClient == client)
   return pCur;
 }
 return NULL;
}

/* * function 计算客户端连接数 * param client表示一个客户端对象 * return 返回连接数 */
int CountCon()
{
 int iCount = 0;
 pClient pCur = head;
 while (pCur = pCur->next)
  iCount++;
 return iCount;
}

/* * function 清空链表 * return 无返回值 */
void ClearClient()
{
 pClient pCur = head->next;
 pClient pPre = head;
 while (pCur)
 {
  //head->1->2->3->4,先删除1,head->2,然后free 1
  pClient p = pCur;
  pPre->next = p->next;
  free(p);
  pCur = pPre->next;
 }
}

/* * function 检查连接状态并关闭一个连接 * return 返回值 */
void CheckConnection()
{
 pClient pclient = GetHeadNode();
 while (pclient = pclient->next)
 {
  if (send(pclient->sClient, "", sizeof(""), 0) == SOCKET_ERROR)
  {
   if (pclient->sClient != 0)
   {
    printf("Disconnect from IP: %s,UserName: %s\n", pclient->IP, pclient->userName);
    char error[128] = { 0 }; //发送下线消息给发消息的人
    sprintf(error, "The %s was downline.\n", pclient->userName);
    send(FindClient(pclient->ChatName), error, sizeof(error), 0);
    closesocket(pclient->sClient); //这里简单的判断:若发送消息失败,则认为连接中断(其原因有多种),关闭该套接字
    RemoveClient(pclient->flag);
    break;
   }
  }
 }
}

/* * function 指定发送给哪个客户端 * param FromName,发信人 * param ToName, 收信人 * param data, 发送的消息 */
void SendData(char* FromName, char* ToName, char* data)
{
 SOCKET client = FindClient(ToName); //查找是否有此用户
 char error[128] = { 0 };
 int ret = 0;
 if (client != INVALID_SOCKET && strlen(data) != 0)
 {
  char buf[128] = { 0 };
  sprintf(buf, "%s: %s", FromName, data); //添加发送消息的用户名
  ret = send(client, buf, sizeof(buf), 0);
 }
 else//发送错误消息给发消息的人
 {
  if(client == INVALID_SOCKET)
   sprintf(error, "The %s was downline.\n", ToName);
  else
   sprintf(error, "Send to %s message not allow empty, Please try again!\n", ToName);
  send(FindClient(FromName), error, sizeof(error), 0);
 }
 if (ret == SOCKET_ERROR)//发送下线消息给发消息的人
 {
  sprintf(error, "The %s was downline.\n", ToName);
  send(FindClient(FromName), error, sizeof(error), 0);
 }

}

<
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • socket多人聊天程序C语言版(二)
  • socket多人聊天程序C语言版(一)
  • 用C语言进行最基本的socket编程
  • C语言中等待socket连接和对socket定位的方法
  • C语言中socket相关网络编程函数小结
  • C语言设置和取得socket状态的相关函数用法
  • C语言实现Linux下的socket文件传输实例
  • C语言实现socket简单通信实例
  • C语言socket编程开发应用示例

相关文章

  • 2017-05-28详细总结C++的排序算法
  • 2017-05-28C++改变编程入口为main函数
  • 2017-05-28Windows消息传递机制详解
  • 2017-05-28vector与map的erase()函数详细解析
  • 2017-05-28LintCode-排序列表转换为二分查找树分析及实例
  • 2017-05-28用VC++6.0的控制台实现2048小游戏的程序
  • 2017-05-28C++内核对象封装单实例启动程序的类
  • 2017-05-28浅谈C++基类的析构函数为虚函数
  • 2017-05-28wince禁止程序标题栏上的退出按钮示例
  • 2017-05-28利用ace的ACE_Task等类实现线程池的方法详解

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • 如何正确的使用语句块
    • string与char*转换的使用详解
    • c语言快速排序算法示例代码分享
    • 将CString字符串输入转化成整数的实现方法
    • 详解C++文件读写操作
    • C语言实现字符转unix时间戳的简单实例
    • C++中vector和map的删除方法(推荐)
    • C++之异常处理详解
    • C++中I/O模型之select模型实例
    • 讲解C语言编程中指针赋值的入门实例

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有