基于UDP的P2P聊天工具 0.2

简介:
1)这也是一个windows的P2P聊天工具;
2)它修复了0.1版的一个bug;
3)它为0.3版做了一点准备;

相关内容:
1)如果对端端口未开启服务,对socket调用send函数,会发生什么?
2)如何自定义应用层的传输协议?

一、向未开启服务的端口发送数据报
如果向未开启服务的端口发送数据,那么对端就会返回一个RST分节。除了这个知识点,还需要关心的就是send/recv是否会因此产生什么变化。

先回顾一下0.1版中,我提供的那个启动脚本start.bat。

@echo off
if exist ./Talker.exe (start Talker.exe 33333 127.0.0.1 44444start Talker.exe 44444 127.0.0.1 33333
) else (echo "./Talker.exe does not exist"pause
)

它几乎同时启动了两个相对的Talker。这掩盖了0.1版Talker的一个bug。而如果我们只启动了一个Talker,那么在发出第一个字符串时,程序就会退出。

回到“向未开启服务的端口发送数据”这个话题。
1)对于send来说,尽管对方服务未开,调用和返回都是不受影响的。因为它只是将数据拷到内核缓冲区,就完成任务了。
2)而对于recv,它会返回-1。这个时候,可以根据错误码了解发生了什么。在linux可以根据errno,而windows中则可以使用WSAGetLastError()获取错误码。将错误码输出,显示10054;再在winerror.h中查看,对应的宏定义为WSAECONNRESET。这个就表示收到了RST。

再说0.1版。在recv收到RST,并返回-1后,直接调用了exit(WSAGetLastError())。这使得整个程序直接退出了。一种简单的做法是改为return(WSAGetLastError())。不过这样一来似乎少了点什么。

考虑Talker::Recv()的返回值。较好的做法是返回成功读取的数据长度,而在失败时返回错误码。所以较好的做法是,recv失败时返回-1*WSAGetLastError()。这样,Talker可以及时的判断对方是否在线。
修改部分如下:

int Talker::Recv(char * buf, int len)
{int size = recv(m_sockfd, buf, len, 0); if (size < 0){   return(-1*WSAGetLastError());}       return size;
}
void Talker::Start()
{printf("talking ...\n");    HANDLE handle = CreateThread(NULL, 0, ThreadFunc, this, 0, NULL);   while (true){char buf[MAXBYTE] = { 0 };int size = Recv(buf, sizeof(buf));      if (size > 0){printf("from peer: %s\n", buf);         }else if (size == -WSAECONNRESET){printf("%s\n", "peer is not online.");}Sleep(1000);}
}

二、自定义应用层的传输协议
当我们需要传输字符串意外的数据时,经常需要定义一个传输协议。它可以用来协定数据长度,校验方式,时间参数等。但这里我们只考虑最粗糙的方式。
一般可以有两种方式:固定长度和不定长度。
1)固定长度
假设要传输的数据的类型为Msg,数据报的格式可以像这样:

#pragma pack(push,1)
struct Msg
{int len;char data[MAXBYTE];
};
#pragma pack(pop)

这里的#pragma pack(push,1)类似与#pragma(1),可以让结构体内的数据更紧密。具体请参见结构体对齐方面的知识。在传输时可以这样:

char* data = "test";
Msg msg;
msg.len = strlen(data)+1;
memmove(msg.data, data, msg.len);send(sockfd, (const char*)&msg, sizeof(Msg));

接收时可以这样:

char buf[MAXBYTE] = {0};
recv(sockfd, buf, sizeof(buf));
Msg * pMsg = (Msg*)buf;

2)不定长度
将Msg结构做一个修改,像这样:

#pragma pack(push,1)
struct Msg
{int len;char data[0];
};
#pragma pack(pop)

输出sizeof(Msg)sizeof(int)是相等的。这说明Msg结构中的data[0]不占用结构体的空间。具体请参加柔性数组方面的定义。

柔性数组是不占用结构体空间的,但是当我们给Msg开出大于sizeof(Msg)的内存空间时,多出来的部分就可以像data数组一样使用了。

从结构的角度来讲,Msg是一个数据头,data[0]管理的就是数据体。假设我们需要发送一个5个字节的数据,像这样:

char * data = "test";
Msg * pMsg = (Msg*)new char[sizeof(Msg)+strlen(data)+1];
pMsg->len = strlen(data)+1;
memmove(pMsg->data, data, pMsg->len);send(sockfd, (const char*)pMsg, sizeof(Msg)+pMsg->len);
delete pMsg;

接收时的处理可以像这样:

char buf[MAXBYTE] = {0};
recv(sockfd, buf, sizeof(buf));int len = ((Msg*)buf)->len;
Msg * pMsg = (Msg*)new char[sizeof(Msg)+len];
pMsg->len = len;
memmove(pMsg->data, buf, len);delete(pMsg);

三、字节序
如果你按照上面提到的自定义协议进行数据传输时,会发现一个有意思的问题:没考虑网络字节序~。

四、补充于2017/12/18
在0.5版中,对消息协议做了修改:取消了柔性数组的使用,并使用数据包头/体的结构形式。数据体使用stl的string进行处理。若有兴趣,可以看看这里。

基于UDP的P2P聊天工具——0.2相关推荐

  1. 基于UDP的P2P聊天工具 0.3——消息队列和重传

    基于UDP的P2P聊天工具 0.3--消息队列和重传 简介: 1)这是一个Windows的P2P聊天工具: 2)相比0.2,它多了定时重传的机制: 3)对局域网来说有些鸡肋,就当是为跨局域网做准备吧: ...

  2. Android基于UDP的局域网聊天通信

    代码地址如下: http://www.demodashi.com/demo/12057.html 记得把这几点描述好咯:代码实现过程 + 项目文件结构截图 + 演示效果 1. 开发环境 1.1 开发工 ...

  3. 基于Socket的简易聊天工具

    文章目录 基于Socket的简易聊天工具 简易聊天工具的功能: 项目设计 1.界面设计 2.类的设计 程序编写 1.ChatServer 2.ChatFrame 窗体的设计 1.ChatFrame的窗 ...

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

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

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

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

  6. 基于WebServices简易网络聊天工具的设计与实现

    基于WebServices简易网络聊天工具的设计与实现 Copyright 朱向洋 Sunsea ALL Right Reserved 一.项目内容 本次课程实现一个类似QQ的网络聊天软件的功能:服务 ...

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

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

  8. 基于TCP的QQ聊天工具

    ###前言: 基于JAVA语言开发的一款网络聊天工具,通过Socket实现TCP编程,使用多线程实现了多客户端的连接.模仿腾讯QQ的界面,功能较为简单,但是使用了最基本的网络编程技术,如socket. ...

  9. Java网络编程——基于UDP协议的聊天室

    UDP简述    UDP(User Datagram Protocol)协议是Internet 协议集支持的一个无连接的传输协议,中文名为用户数据报协议.它为应用程序提供了一种无需建立连接就可以发送封 ...

最新文章

  1. React router 的 Route 中 component 和 render 属性理解
  2. MyEclipse安装SVN插件之超级精简法
  3. 计算机视觉:数据预处理-图像增广方法
  4. Xmind settings lower
  5. Linux 下升级 python2 到python3
  6. DbVisualizer简单介绍
  7. JAVA复习5(集合——ArrayList)
  8. 万年历升级版 Calendar
  9. appium更新到1.8.2,不能打开运行的解决办法
  10. Java Calendar getDisplayName()方法与示例
  11. 信息学奥赛一本通(1324:【例6.6】整数区间)
  12. 商务搜索引擎_网络营销外包——网络营销外包公司如何做好电子商务网站优化?...
  13. 传聊天宝团队解散 罗永浩已退出股东行列
  14. php数组去重复数据的小例子
  15. vim编辑器的基本使用
  16. 何时该开始写测试代码
  17. jqueryAjax在客户端发送请求的方式(摘抄!)
  18. Vulkan学习(一):Vulkan环境搭建(Windows)官方教程--(Base code Instance Validation layers)
  19. python 3d绘图模块_使用python和mayavi创建3D streamplot
  20. python怎么把小写改成大写_Python 把金额小写转换成大写

热门文章

  1. dm.jdbc.driver.DMException: 网络通信异常
  2. 论文阅读:A ConvNet for the 2020s
  3. IOS开发之——新浪微博(42)
  4. DSP SPI串行外设接口
  5. android 平台的RNDIS功能
  6. 网址导航网站源码 Guojiz网址导航系统V 5.3正式版
  7. python爬取机票信息
  8. AlertDialog替代ProgressDialog方案
  9. fedora17 安装 飞鸽传书 问题整理
  10. 程序员,你离年薪100万差什么?