1.同上两篇,学校的实验。

但是这第三个实验坑比较多,写了好长时间,百度了好久才写对。

我是先启动的服务器,在启动数据包捕获,最后在启动客户端,这样最初的通信也能捕获到。而且我的客户端与服务器时双向通信,也就是两者都会经过“127.0.0.1”这个地址,所以客户端的消息和服务器的消息都会捕获到。、

捕获之后根据IP报文结构还有TCP报文结构来推算内容啊,开始位置在哪个地方,这个也与自己定义的头文件有关。

2.  数据包捕获

//.h文件
#pragma once//IP报文格式
typedef struct IP {//unsigned char version;//4位IP版本号unsigned char headLen;//4位首部长度unsigned char serviceType;//8位服务类型unsigned short totalLen;//16位总长度unsigned short identifier;//16位标识符unsigned short flags;//3位标志位//unsigned short fragOffset;//13位片偏移unsigned char timeToLive;//8位生存时间unsigned char protocal;//8位协议unsigned short headCheckSum;//16位首部校验和unsigned int sourceAddr;//32位源地址unsigned int destinAddr;//32位目的地址
}IPHeader;//TCP报文格式
typedef struct TCP {unsigned short sourcePort;//16位源端口号unsigned short destinPort;//16位目的端口号unsigned int seqNum;//32位序列号unsigned int ackNum;//32位确认号unsigned char headLen;//4位首部长度//unsigned char resv;//4位保留字unsigned char flags;//8位标志位unsigned short winSize;//16位窗口大小unsigned short checkNum;//16位校验和unsigned short urgPointer;//16位紧急指针
}TCPHeader;
//.cpp文件
#include <WinSock2.h>
#include <iostream>
#include "headers.h"
using namespace std;#pragma comment(lib,"ws2_32.lib")#define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)//将SIO_RCVALL定义为_WSAIOW(IOC_VENDOR,1)int main() {IP* ip;TCP* tcp;WSADATA wsd;if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) {cout << "error:" << WSAGetLastError() << endl;return -1;}SOCKET sock;sock = socket(AF_INET, SOCK_RAW, IPPROTO_IP);if (sock == INVALID_SOCKET) {cout << "error:" << WSAGetLastError() << endl;closesocket(sock);WSACleanup();return -2;}BOOL flag = true;if (setsockopt(sock, IPPROTO_IP, 2, (char*)&flag, sizeof(flag)) == SOCKET_ERROR) {cout << "error:" << WSAGetLastError() << endl;closesocket(sock);WSACleanup();return -3;}/*创建了原始套接字后,就要设置套接字选项,这要通过setsocketopt函数来实现,setsocketopt函数的声明如下:int setsocketopt (SOCKET s,int level,int optname,const char FAR *optval,int optlen );参数s是标识套接口的描述字,要注意的是选项对这个套接字必须是有效的。参数Level表明选项定义的层次,对TCP/IP协议族而言,支持SOL_SOCKET、IPPROTO_IP和IPPROTO_TCP层次。参数Optname是需要设置的选项名,这些选项名是在Winsock头文件内定义的常数值。参数optval是一个指针,它指向存放选项值的缓冲区。参数optlen指示optval缓冲区的长度*/SOCKADDR_IN addr;addr.sin_family = AF_INET;addr.sin_port = htons(0);addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");if (bind(sock, (struct sockaddr*) &addr, sizeof(addr)) == SOCKET_ERROR) {cout << "error:" << WSAGetLastError() << endl;closesocket(sock);WSACleanup();return -4;}DWORD dwBytesReturned;DWORD dwBufferInLen = 1;//将网卡设置为混听模式,就是接收所有数据if (ioctlsocket(sock, SIO_RCVALL, &dwBufferInLen) == SOCKET_ERROR) {cout << "error:" << WSAGetLastError() << endl;closesocket(sock);WSACleanup();return -5;}/*ioctsocket功能是控制套接口的模式。可用于任一状态的任一套接口。它用于获取与套接口相关的操作参数,而与具体协议或通讯子系统无关。int ioctlsocket( int s, long cmd, u_long * argp);s:一个标识套接口的描述字。cmd:对套接口s的操作命令。argp:指向cmd命令所带参数的指针。*/int bytesRecv;char buffer[65535];//接收缓冲区的内容//SOCKADDR_IN from;struct sockaddr_in from;int fromSize = sizeof(from);//循环监听;while (true) {memset(buffer, 0, 65535);bytesRecv = recvfrom(sock, buffer, 65535, 0, (struct sockaddr*) &from, &fromSize);if (bytesRecv == SOCKET_ERROR) {cout << "error:" << WSAGetLastError() << endl;closesocket(sock);WSACleanup();return -6;}/*与recv的功能差不多,都是接收数据,但是from可以适用于UDP,因为多了一个from,你懂的。*/ip = (struct IP*)buffer;if (ip->protocal == 6) {//过滤其他协议,只留下TCP协议tcp = (struct TCP*)(buffer + (4 * ip->headLen & 0xf0 >> 4));//得到TCP头cout << "Network+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";//网络层数据cout << "IP报文字节数:" << bytesRecv << "\n";cout << "源IP:" << inet_ntoa(*(in_addr*)&ip->sourceAddr) << "\n";cout << "目的IP:" << inet_ntoa(*(in_addr*)&ip->destinAddr) << "\n";cout << "Transportation++++++++++++++++++++++++++++++++++++++++++++++++++++\n";//运输层数据cout << "源端口:" << ntohs(tcp->sourcePort) << "\n";cout << "目的端口:" << ntohs(tcp->destinPort) << "\n";cout << "Applications++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";//应用层数据char* start = buffer + 5 + 4 * ((tcp->headLen & 0xf0) >> 4 | 0);//计算数据头指针,从何处开始数据int dataSize = bytesRecv - 5 - 4 * ((tcp->headLen & 0xf0) >> 4 | 0);//计算数据长度cout << "数据内容:";memcpy(buffer, start, dataSize);for (int i = 0; i < dataSize; i++) {if (buffer[i] >= 32 && buffer[i] < 255) {printf("%c", (unsigned char)buffer[i]);}else {printf(".");}}cout << "\n";}}}

3.服务器端

#include<WinSock2.h>
#include <iostream>
using namespace std;#pragma comment(lib,"ws2_32.lib")DWORD WINAPI clientChildThread(LPVOID ipParameter) {SOCKET clientSocket = (SOCKET)ipParameter;int const CLIENT_MSG_SIZE = 128;//接收缓冲区长度char inMSG[CLIENT_MSG_SIZE];//接收信息的char数组char outMSG[CLIENT_MSG_SIZE];//存储时间的char数组char wx[] = "无效的命令";int size;while (true) {memset(inMSG, 0, CLIENT_MSG_SIZE);//接收消息之前清空接收消息数组size = recv(clientSocket, inMSG, CLIENT_MSG_SIZE, 0);//接收消息if (size == SOCKET_ERROR) {//如果接收消息出错cout << "对话中断,错误提示:" << WSAGetLastError() << endl;closesocket(clientSocket);break;}//否则,输出消息cout << "客户端消息:" << inMSG << endl;//如果客户端请求当前时间if (strcmp(inMSG, "当前时间") == 0) {SYSTEMTIME systime = { 0 };GetLocalTime(&systime);//获取系统时间sprintf(outMSG, "%d-%02d-%02d %02d:%02d:%02d",systime.wYear, systime.wMonth, systime.wDay,systime.wHour, systime.wMinute, systime.wSecond);send(clientSocket, outMSG, CLIENT_MSG_SIZE, 0);memset(outMSG, 0, CLIENT_MSG_SIZE);//每次回复之后,清空发送消息数组}//如果客户端要退出连接else if (strcmp(inMSG, "退出连接") == 0) {closesocket(clientSocket);cout << "客户端退出连接成功" << endl;break;}else {send(clientSocket, wx, sizeof(wx), 0);}}return 0;
}int main() {WSADATA wsd;if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) {WSACleanup();return  -1;}SOCKET serverSocket;serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (serverSocket == INVALID_SOCKET) {cout << "error:" << WSAGetLastError() << endl;WSACleanup();return -2;}SOCKADDR_IN server;server.sin_family = AF_INET;server.sin_port = htons(2591);server.sin_addr.S_un.S_addr = htonl(INADDR_ANY);if (bind(serverSocket, (struct sockaddr*) &server, sizeof(server)) == SOCKET_ERROR) {cout << "error:" << WSAGetLastError() << endl;closesocket(serverSocket);WSACleanup();return -3;}if (listen(serverSocket, 2) == SOCKET_ERROR) {cout << "error:" << WSAGetLastError() << endl;closesocket(serverSocket);WSACleanup();return -4;}cout << "服务器启动。。。监听中。。。" << endl;SOCKET clientSocket;SOCKADDR_IN client;int addrsize = sizeof(SOCKADDR_IN);HANDLE pThread;while (true) {clientSocket = accept(serverSocket, (struct sockaddr*) &client, &addrsize);if (clientSocket == INVALID_SOCKET) {cout << "客户端accept失败,错误提示:" << WSAGetLastError() << endl;closesocket(serverSocket);WSACleanup();return -5;}else {cout << "客户端\n"<< inet_ntoa(client.sin_addr)//inet_ntoa将一个十进制网络字节序转换为点分十进制IP格式的字符串。<< "\n通过端口:\n"<< ntohs(client.sin_port)//ntohs将一个16位数由网络字节顺序转换为主机字节顺序<< "\n连接成功" << endl;pThread = CreateThread(NULL, 0, clientChildThread, (LPVOID)clientSocket, 0, NULL);/*lpsa:线程句柄的安全性,比如子进程是否可以继承这个线程句柄,一般设置为NULLcbStack:线程栈大小,一般取0表示默认大小lpStartAddr:线程入口函数lpvThreadParam:线程入口函数的参数fdwCreate:控制线程创建的标志,一般为0,表示线程立即启动。也可以选择可以挂起,使用CREATE_SUSPENDED,之后在代码中使用ResumeThread启动。lpIDThread:线程的ID值,接收线程返回的ID*/if (pThread == NULL) {cout << "创建子进程失败。" << endl;break;}CloseHandle(pThread);}}closesocket(serverSocket);closesocket(clientSocket);WSACleanup();return 0;}

4.客户端

#include<WinSock2.h>
#include <iostream>
using namespace std;#pragma comment(lib,"ws2_32.lib")int main() {WSADATA wsd;//定义 WSADATA对象if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) {//初始化WSAWSACleanup();return -1;}SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (clientSocket == INVALID_SOCKET) {cout << "error:" << WSAGetLastError() << endl;WSACleanup();return -2;}SOCKADDR_IN client;client.sin_family = AF_INET;client.sin_port = htons(2591);client.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");int const SERVER_MSG_SIZE = 128;char inMSG[SERVER_MSG_SIZE] = { 0 };//用户输入的消息char outMSG[SERVER_MSG_SIZE];//要发送给服务器的消息//连接服务器失败if (connect(clientSocket, (struct sockaddr*) &client, sizeof(client)) < 0) {cout << "error:" << WSAGetLastError() << endl;closesocket(clientSocket);WSACleanup();return -3;}//连接服务器成功else {cout << "连接服务器成功。。。。。。\n" << endl;while (true) {memset(outMSG, 0, SERVER_MSG_SIZE);cout << "请输入请求。。。。。。:" << endl;cin >> outMSG;send(clientSocket, outMSG, SERVER_MSG_SIZE, 0);if (strcmp(outMSG, "退出连接") == 0) {break;}int size = recv(clientSocket, inMSG, SERVER_MSG_SIZE, 0);cout << "服务器端回答:" << inMSG << endl;memset(inMSG, 0, SERVER_MSG_SIZE);}}closesocket(clientSocket);WSACleanup();system("pause");return 0;}

原始套接字编程(C++)相关推荐

  1. 【Linux网络编程】原始套接字编程

    原始套接字编程和之前的 UDP 编程差不多,无非就是创建一个套接字后,通过这个套接字接收数据或者发送数据.区别在于,原始套接字可以自行组装数据包(伪装本地 IP,本地 MAC),可以接收本机网卡上所有 ...

  2. linux sock_raw原始套接字编程

    sock_raw原始套接字编程可以接收到本机网卡上的数据帧或者数据包,对与监听网络的流量和分析是很有作用的.一共可以有3种方式创建这种socket   1.socket(AF_INET, SOCK_R ...

  3. Linux网络编程——原始套接字编程

    Linux网络编程--原始套接字编程 转自:http://blog.csdn.net/tennysonsky/article/details/44676377 原始套接字编程和之前的 UDP 编程差不 ...

  4. 原始套接字编程”中的Teardrop代码编程

    原始套接字编程"中的Teardrop代码编程 (1)实验代码: #include <stdio.h> #include <stdlib.h> #include < ...

  5. 原始套接字编程 | ping程序实现

    [实验目的] 熟悉原始套接字编程的基本流程 理解ping程序的实现机制 理解ICMP协议的基于作用和报文格式. 完成原始套接字的配置. [实验内容] 1.构造ICMP协议首部结构 2.构造IC ...

  6. 原始套接字编程(1)

    Linux下原始套接字的原理 创建原始套接字: socket(AF_NET, SOCK_RAW, protocol); 1. 参数protocol用来致命所接收的协议包,如果是像IPPROTO_TCP ...

  7. Teardrop原始套接字编程

    目录 一.含义介绍 二.Teardrop代码编程 参考 一.含义介绍 1.什么是原始套接字 原始套接字的含义就是在传输层之下使用的套接字,它提供了一些 TCP 和 UDP 套接字无法提供的功能,即: ...

  8. Windows平台的原始套接字编程的知识点概要(备忘)

    其实从大学学习了C语言后,翻看整本教材只有C语言的语法,根本没有网络编程相关的任何内容,现在回想起来,都记不起自己何时在哪本书上学习了套接字编程,说起TCP.UDP,能知道他们的区别,相关的编程的&q ...

  9. 105-网络编程——第七章原始套接字编程(上)

    1.原始套接字是允许访问底层传输协议的一种套接字类型,提供了普通套接字所不具备的功能,能够对网络数据包进行某种程度的控制操作 因此原始套接字通常用于开发简单网络性能监视程序以及网络探测.网络攻击 2. ...

  10. 原始套接字编程——Teardrop

    文章目录 一.介绍套接字 二.著名的Teardrop 三.伪造虚假地址的IP包 四.在Ubuntu下使用Wireshark抓包进行验证 五.总结 六.参考资料 一.介绍套接字 流套接字(SOCK_ST ...

最新文章

  1. aws 认证_引入#AWSCertified挑战:您的第一个AWS认证之路
  2. 【错误记录】Android Studio 编译时 Kotlin 代码编译报错 ( Not enough information to infer type variable T )
  3. Laravel - Artisan 个人常用总结
  4. 673. Number of Longest Increasing Subsequence
  5. JAVA判定参数类型进行赋值_java – 为什么泛型方法在赋值中更改了参数化类型?...
  6. 【英语学习】【WOTD】cumulate 释义/词源/示例
  7. 七秘诀工作效率与薪水翻番
  8. Asp.net MVC3.0 入门指南 6 审视编辑方法和视图
  9. centos mysql lujin_MySQL中文转换成拼音的函数[zt]
  10. 小爱mini改aux立体声_拆解报告:Redmi小爱音箱Play
  11. caj文件添加endnote_endnote怎么导入caj
  12. PW4052锂电池充电管理芯片2.5A 单节(多并)锂 电池充电管理
  13. 嵌入式系统上电,程序的运行过程
  14. 液相色谱柱PHP,浅谈液相色谱柱现代史
  15. 卡拉OK歌词原理和实现高仿Android网易云音乐
  16. mpstat命令(linux cpu监控工具)
  17. Thinkpad 系列电脑,装win10无限卡死在登录界面 解决方案及bug report!
  18. 【hadoop】MultipleOutputFormat和MultipleOutputs
  19. VSG多机并联系统小信号建模
  20. 【数据聚类】基于改进的粒子群算法优化K-means算法实现数据分类含Matlab源码

热门文章

  1. 关闭后台App刷新后台应用刷新是做什么的
  2. 运动类计算公式----卡路里计算
  3. 【官宣】传智教育使命升级!
  4. 真是恍然大悟啊!成功拿下美团offer,真香
  5. 内存不足够怎么办,swap空间来相伴
  6. Android 透明状态栏及设置状态栏字体颜色
  7. 日常生活补充维生素C需要选对吃法
  8. pyqtgraph:GLSurfacePlotItem如何在三维地形表面自定义颜色分布(读取图片给三维平面分区域着色)
  9. 记2018年8月Android面试分享
  10. 管理:没有调查就没有发言权