四十九C-137 - 计算机网络
type: channel
link: https://joessem.com/tag/计算机网络
items: PyQt5+poplib+smtplib+python3.6邮件客户端Demo
items: Scapy+PyQt5+Python3.6实现网络嗅探器Demo
items: 局域网IP多播
items: Tracert 与 Ping程序设计与实现（二）
items: Tracert 与 Ping程序设计与实现（一）
items: 网络聊天程序的设计与实现

PyQt5+poplib+smtplib+python3.6邮件客户端Demo
type: item
date: 2019-12-27T14:21:29+08:00
description: 目录：准备代码运行演示准备安装库：PyQt5，poplib，smtplib邮件客户端主要功能包括接收邮件、发送邮件、邮件分类.........，时间有限，只做出了发送邮件和接收邮件。接收邮件主要依赖pop服务器，发送邮件依赖smtp服务器，例如网易163邮箱的pop服务器为pop.163.com，smtp服务器为smtp.163.com，发送端口为465。目前测试网易邮箱没有问题，但是使用前确保打开了163的 POP3/SMTP/IMAP 服务，及开启 客户端授权密码。代码包含三个界面，可使用QTdesigner设计GUI，也可直接使用我生成的界面py文件。三个界面如下：ui生成的代码分别是：主界面ui --> pop3.py# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'pop3.ui' # # Created by: PyQt5 UI code generator 5.13.0 # # WARNING! All changes made in this file will be lost! from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(551, 716) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.tableWidget = QtWidgets.QTableWidget(self.centralwidget) self.tableWidget.setGeometry(QtCore.QRect(30, 70, 501, 231)) self.tableWidget.setObjectName("tableWidget") self.tableWidget.setColumnCount(5) self.tableWidget.setRowCount(0) item = QtWidgets.QTableWidgetItem() self.tableWidget.setHorizontalHeaderItem(0, item) item = QtWidgets.QTableWidgetItem() self.tableWidget.setHorizontalHeaderItem(1, item) item = QtWidgets.QTableWidgetItem() self.tableWidget.setHorizontalHeaderItem(2, item) item = QtWidgets.QTableWidgetItem() self.tableWidget.setHorizontalHeaderItem(3, item) item = QtWidgets.QTableWidgetItem() self.tableWidget.setHorizontalHeaderItem(4, item) self.tableWidget.horizontalHeader().setDefaultSectionSize(150) self.label = QtWidgets.QLabel(self.centralwidget) self.label.setGeometry(QtCore.QRect(30, 30, 61, 21)) self.label.setObjectName("label") self.pushButton = QtWidgets.QPushButton(self.centralwidget) self.pushButton.setGeometry(QtCore.QRect(360, 20, 81, 31)) self.pushButton.setObjectName("pushButton") self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget) self.pushButton_2.setGeometry(QtCore.QRect(110, 20, 81, 31)) self.pushButton_2.setObjectName("pushButton_2") self.pushButton_3 = Q…

Scapy+PyQt5+Python3.6实现网络嗅探器Demo
type: item
date: 2019-12-26T09:53:24+08:00
description: 目录：准备代码运行演示准备基于python3.6，PyQt5，Scapy.windows 下使用Scapy可能出现Error:Sniffing and sending packets is not available at layer 2:......，安装 winPcap 可有效解决。PyQt5 的安装及环境配置：PyQt5中文文档： http://code.py40.com/pyqt5/安装请参考： https://blog.csdn.net/m0_37606112/article/details/78419892环境配置请参考： https://blog.csdn.net/lyzwjaa/article/details/79429901第一个Demo请参考： https://blog.csdn.net/px41834/article/details/79383985Scapy官方文档：https://scapy.readthedocs.io/en/latest/installation.htmlscapy.sniff()函数解析：Sniff方法定义：sniff(filter="",iface="any", prn=function, count=N)filter的规则使用 Berkeley Packet Filter (BPF)语法。iface用来指定要在哪个网络接口上进行抓包（通常不指定即所有网络接口）prn指定回调函数，每当一个符合filter的报文被探测到时，就会执行回调函数，通常使用lambda表达式来写回调函数count指定最多嗅探多少个报文（是指符合filter条件的报文，而非所有报文）GUI设计设计了之后请使用 pyuic5 将ui转为py文件。代码注意：import demo->demo为你的GUI的py文件import sys import demo from PyQt5.QtWidgets import QApplication,QMainWindow,QAbstractItemView,QTableWidgetItem from scapy.all import * import _thread from PyQt5.QtCore import QCoreApplication app = QApplication(sys.argv) MainWindow = QMainWindow() ui = demo.Ui_MainWindow() ui.setupUi(MainWindow) ui.tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows) msg = {1:"ICMP", 6:"TCP", 17:"UDP", 40:"Others", 2054:"ARP"} # 报文种类 def display(sniff_data): rrow = ui.tableWidget.rowCount() ui.tableWidget.insertRow(rrow) ui.tableWidget.setItem(rrow, 0, QTableWidgetItem(sniff_data['from'])) ui.tableWidget.setItem(rrow, 1, QTableWidgetItem(sniff_data['to'])) ui.tableWidget.setItem(rrow, 2, QTableWidgetItem(sniff_data['msg_type'])) ui.tableWidget.setItem(rrow, 3, QTableWidgetItem(sniff_data['data'])) def getoptData(pkt): pkt.show() print(pkt[0].type) sniff_data = {} if int(pkt[0].type) == 2048: sniff_data['from'] = str(pkt[1].src) sniff_data['to'] = str(pkt[1].dst) try: sniff_data['msg_type'] = str(msg[int(pkt[1].proto)]) except: sniff_data['msg_type'] = str(msg[40]) try: sniff_data['data'] = str(pkt[3]) except: sniff_data['data'] = str("") _thread.start_new_thread(display, (sniff_data,)) elif int(pkt[0].type) ==…

局域网IP多播
type: item
date: 2019-12-24T17:10:09+08:00
description: 目录：知识储备代码运行效果知识储备接收端重点：(1)、创建一个 SOCK_DGRAM 类型的 Socket。(2)、将此 Socket 绑定到本地的一个端口上，为了接收服务器端发送的多播数据。(3)、加入多播组。(4)、接收多播数据。发送端重点：(1)、创建一个 SOCK_DGRAM 类型的 Socket。(2)、加入多播组。(3)、发送多播数据。当一台主机想要同时接收或者发送时，必须绑定相同的端口号。在网络中，线程的控制是非常重要的，在此实验中我采用了双线程，主线程用于监听发送端，副线程用于监听接收端。我编不下去了，自己看代码吧。采用QT creator平台，项目文件目录如下：首先添加库：在untitled.pro文件中任意空白行插入 LIBS += -lWs2_32GUI布局为：代码mainwindow.h 用于声明一下全局变量。#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include "thread.h" #include <iostream> #include <winsock2.h> #include <ws2tcpip.h> #include <stdio.h> #include <stdlib.h> class TestThread; //全局变量声明 extern struct sockaddr_in remote,local,from; extern SOCKET sock,sockM; namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: void on_pushButton_clicked(); void receiver(char*,char*); void on_pushButton_2_clicked(); private: Ui::MainWindow *ui; TestThread *Thread; }; #endif // MAINWINDOW_Hthread.h 用于创建线程类：#ifndef TESTTHREAD_H #define TESTTHREAD_H #include <QThread> #include "mainwindow.h" class TestThread : public QThread { Q_OBJECT public: explicit TestThread(QObject *parent = 0); protected: void run(); signals: void TestSignal(char*,char*); private: int tnc=4; }; #endif // TESTTHREAD_H main.cpp 无需改动mainwindow.cpp 中绑定按钮监听事件和发送消息#include "mainwindow.h" #include "ui_mainwindow.h" #include <iostream> #include <winsock2.h> #include <ws2tcpip.h> #include <stdio.h> #include <stdlib.h> #define MCASTADDR "233.0.0.1" //本例使用的多播组地址。 #define MCASTPORT 5150 //本地端口号。 #define BUFSIZE 1024 //发送数据缓冲大小。 //#pragma comment(lib,"ws2_32") using namespace std; SOCKET sock,sockM; struct sockaddr_in remote,local; void MainWindow::receiver(char* recvbuf,char* ipadd){ cout<<ipadd << "+"<<recvbuf <<endl; QString recvip = QString::fromLocal8Bit(ipadd); QString recvtext = QString::fromLocal8Bit(recvbuf); ui->textEdit->textCursor().insertText("<"+recvip+"> : \n "+recvtext+"\n"); } MainWindow::MainWindow(QWidget *…

Tracert 与 Ping程序设计与实现（二）
type: item
date: 2019-12-22T12:56:21+08:00
description: 2019/12/24update：已解决线程并发导致主界面假死问题。 今天是冬至，祝大家有个愉快的的冬天。o(*￣▽￣*)o花了一天的时间给程序做了一个GUI，在调试多线程的时候遇到了困难，昨天晚上2点多才弄完，但是感觉这个多线程有点奇怪（雾目录：提示代码运行演示提示我用的GUI开发环境是Qt Creator。Qt的下载地址和安装步骤看 这里 。Qt creator的语法和C++一样，只不过在C++的基础上增加了专门用于图像界面的库，C++代码也可在Creator上流畅运行。开始之前先新创一个项目，命名为Tracert。然后在Tracert.pro文件中添加我们需要用到的库，在任意行添加 "LIBS += -lWs2_32" 即可。然后新建一个头文件threadtest.h和一个资源文件threadtest.cpp，用于创建多线程。在Forms目录下有一个布局文件mainwindow.ui，点击这个ui文件，我们可快捷编辑GUI布局。现在我们的资源目录为：代码mainwindow.h中是我们主要的类，用于GUI和声明一些全局变量：#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include "threadtest.h" class TestThread; extern int ipnumber; extern int nowrow; extern QString nowip; extern int outtime; namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: void DisplayMsg(QString,bool,QString,QString); void on_pushButton_clicked(); void on_pushButton_2_clicked(); private: Ui::MainWindow *ui; TestThread* t[255]; QString ip1; QString ip2; }; #endif // MAINWINDOW_H threadtest.h 头文件用于创建线程类：#ifndef TESTTHREAD_H #define TESTTHREAD_H #include <QThread> #include "mainwindow.h" class TestThread : public QThread { Q_OBJECT public: explicit TestThread(QObject *parent = 0); protected: void run(); signals: void TestSignal(QString,bool,QString,QString); private: int tnc=4; }; #endif // TESTTHREAD_H main.cpp不需要做任何改动：#include "mainwindow.h" #include <QApplication> #include <iostream> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }mainwindow.cpp 就是我们需要重点关注的地方了，GUI的绑定事件及GUI主界面的更新都在此文件内操作，所以代码有点长：#include "mainwindow.h" #include "ui_mainwindow.h" #include <iostream> #include <winsock2.h> #include <ws2tcpip.h> #include <cstring> #include <stdlib.h> #include <stdio.h> #include <string.h> using namespace std; QString nowip; int nowrow; int ipnumber; int outtime; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); WSADAT…

Tracert 与 Ping程序设计与实现（一）
type: item
date: 2019-12-20T13:19:12+08:00
description: 目录：知识储备代码运行演示知识储备此题为我计算机网络期末课程设计的第二题。由于我对GUI的掌握度不高，先暂时不做图形界面。关于ICMP报文和IP报文的详解请阅读教材。以下为需要强调学习的知识：ICMP数据报包括ICMP数据头及ICMP数据部分，IP数据报包括IP数据头及IP数据部分，ICMP数据报将会作为IP数据报的数据部分。ICMP接收的报文种类中其中有两种为：回显应答报文及超时差错报文。利用这两种报文可判断出路由途中的某主机是可达的还是超时的。Tracert的重点是对接收到的数据进行解码，与发送的数据进行对比，判断是否为当前进程发送的数据，以及是否为目的主机返回的数据。代码#include <iostream> #include <winsock2.h> #include <ws2tcpip.h> #include <string> #include <cstring> #include <iostream> #include <stdlib.h> #include <stdio.h> using namespace std; #pragma comment(lib, "Ws2_32.lib") //IP 报头 typedef struct { unsigned char hdr_len:4; //4 位头部长度 unsigned char version:4; //4 位版本号 unsigned char tos; //8 位服务类型 unsigned short total_len; //16 位总长度 unsigned short identifier; //16 位标识符 unsigned short frag_and_flags; //3 位标志加 13 位片偏移 unsigned char ttl; //8 位生存时间 unsigned char protocol; //8 位上层协议号 unsigned short checksum; //16 位校验和 unsigned long sourceIP; //32 位源 IP 地址 unsigned long destIP; //32 位目的 IP 地址 } IP_HEADER; //ICMP 报头 typedef struct { BYTE type; //8 位类型字段 BYTE code; //8 位代码字段 USHORT cksum; //16 位校验和 USHORT id; //16 位标识符 USHORT seq; //16 位序列号 } ICMP_HEADER; //报文解码结构 typedef struct { USHORT usSeqNo; //序列号 DWORD dwRoundTripTime; //往返时间 in_addr dwIPaddr; //返回报文的 IP 地址 } DECODE_RESULT; //计算网际校验和函数 USHORT checksum(USHORT *pBuf,int iSize) { unsigned long cksum=0; while(iSize>1) { cksum+=*pBuf++; iSize-=sizeof(USHORT); } if(iSize) { cksum+=*(UCHAR *)pBuf; } cksum=(cksum>>16)+(cksum&0xffff); cksum+=(cksum>>16); return (USHORT)(~cksum); } //对数据包进行解码，结果封装到Decode当中 /* buf:接收到的buf，字符串 ipacketsize:接收到的数据长度 解析结果封装到DecodeResult ICMP类型， echo_reply是一个常量，放到全局也行 ICMP类型 */ BOOL DecodeIcmpResponse(char * pBuf,int iPacketSize,DECODE_RESULT &DecodeResult,BYTE ICMP_ECHO_REPLY,BYTE ICMP_TIMEOUT) { //检查数据报大小的合法性 IP_HEADER* pIpHdr = (IP_HEADER*)pBuf; //将接收到的数据转换成ip抱头 int iIpHdrLen = pIpHdr->hdr_len * 4;//计算报文长度 //如果接收的报文长度小于IP报文长度，就退出 if (iPacketSize < (int)(iIpHdrLen+sizeof(ICMP_HEADER))) return FALSE; //根据 ICMP 报文类型提取 ID 字段和序列号字段 ICMP_HEADER *pIcmpHdr=(ICMP_HEADER *)(pBuf+iI…

网络聊天程序的设计与实现
type: item
date: 2019-12-16T11:33:21+08:00
description: 基于Socket通信原理。原理请点击 Socket目录:添加库代码运行结果1、添加库编辑环境为CodeBlocks。首先添加要用的库。具体操作为：Settings --> Compiler Settings --> Linker settings，然后点击Add，找到路径 E:\CodeBlocks\MinGW\lib\libws2_32.a （根据CB安装的路径不同自行改变），在右侧输入 -lws2_32，点击OK保存，重启CodeBlocks添加成功。2、代码Server.cpp#include <stdio.h> #include <Winsock2.h> #pragma comment(lib, "WS2_32") // 链接到WS2_32.lib using namespace std; #include <fstream> #include <string> #include <iostream> DWORD WINAPI RECVm(void *Param){ char sendBuf[50];//缓冲区 char recvBuf[50];//缓冲区 char username[50]={0}; // 用户名 SOCKET sockConn = *((SOCKET *)Param); strcpy(sendBuf,"Join in chatroom success!You can start chatting...\n"); send(sockConn,sendBuf,strlen(sendBuf)+1,0);//将数据原样返回 recv(sockConn,recvBuf,50,0); strcpy(username,recvBuf); printf("%s has join in chatting room.\n",username); while(1) { //接收 if(recv(sockConn,recvBuf,50,0)<=0){ printf("%s has exit!\n",username); break; } if(recvBuf!=""){ printf("%s: %s\n",username,recvBuf); } strcpy(recvBuf,""); } closesocket(sockConn); //closesocket(sockSrv); return 0; } int main() { printf("Welcome to chatting room.....\n"); WORD wVersionRequested;//wVersionRequested 是我们要求使用的 WinSock 的版本。 WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 1, 1 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ){ return 0;} if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ){ WSACleanup( ); return 0;} //创建套接字 SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0); //创建sockaddr_in结构体变量,绑定套接字 SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");//通讯地址 addrSrv.sin_family=AF_INET; //sin_family必须为AF_INET,ipv4 addrSrv.sin_port=htons(6000); //端口号 //将套接字和 IP,端口 绑定 bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)); //进入监听状态，后台等待连接队列的最小限制值5 listen(sockSrv,5); //接收 SOCKADDR_IN addrClient; int len=sizeof(SOCKADDR); while(1){ SOCKET sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len); CreateThread(NULL,0,RECVm,&sockConn,0,NULL); } }Client.cpp#include <iostream> #include <stdio.h> #include <Winsock2.h> #pr…