前言

我司有个小程序,用UDP通讯读写设备参数,用来改IP这些出厂参数。
在我所有同事和现场计算机上运行都好使。唯独在我开发本上不好使。
我运维同事让我重装win10, 这哪能听他的…, 这么暴力的主意.

这事是一定要解决的,问题在哪呢?

那个程序有源码, VB6的,写的早了。
前段时间,装了个VB6, 将广播地址改了,当时可以在我开发本上能搜索到设备并改参数。就以为以前同事写的广播地址不大对呗。

前天,给我新做的4G短信猫写插件。
这套软件中,需要连一个我们的带IP的设备,需要先改设备IP.
用原版的UDP程序搜不到设备。
用我改过广播地址的UDP程序也搜不到设备。

用wireshark抓包,发现只有本本用的WLAN网卡上有UDP发包。
USB转网卡那个网卡(设备接在这块临时网卡上)没有收到UDP广播包。

当时的想法:以前同事咋不指定网卡发广播包啊?那自己动手写一个简版的实现吧。

用了1天写完界面和基础代码。今天开始写指定网卡发广播包。
突然发现,windows下的socket不支持发包时指定网卡(setsockopt 选项中就没有 SO_BINDTODEVICE),只有linux才行。。。

那咋弄?
看看能不能调整路由表顺序,将接设备的那块网卡顶到活动路由表的顶部。
试试好使,记录一下。

以前同事跟我说过,将无线网卡禁用,再试试UDP程序好使不?
我现在才明白,他们不是研发,计算机上装的软件少,计算机上可能就只有内置物理网卡和USB转网卡2块网卡。

而我计算机上网卡在系统中的网卡列表处(控制面板\网络和 Internet\网络连接)有5块。

经过试验,不用禁掉其他网卡,只留USB转网卡,那样上网啥的就不行了。
正确姿势是:

  • 将全部网卡都禁掉。
  • 再按照自己想使用的网卡优先级,一个一个启动。那样在活动路由表中,先开启的网卡,就在活动路由表最上面,包优先发向那块网卡。

试验

我接设备的网卡是网卡转USB转出来的。IP是 192.168.2.x
主网卡是内置wifi接我家里的路由器。IP是 192.168.1.x进入系统中的网卡列表处(控制面板\网络和 Internet\网络连接)
将能看到的网卡都禁用了。查看路由表中的活动路由(网卡全禁用)C:\Users\chenx>route print
===========================================================================
接口列表1...........................Software Loopback Interface 1
===========================================================================IPv4 路由表
===========================================================================
活动路由:
网络目标        网络掩码          网关       接口   跃点数127.0.0.0        255.0.0.0            在链路上         127.0.0.1    331127.0.0.1  255.255.255.255            在链路上         127.0.0.1    331127.255.255.255  255.255.255.255            在链路上         127.0.0.1    331224.0.0.0        240.0.0.0            在链路上         127.0.0.1    331255.255.255.255  255.255.255.255            在链路上         127.0.0.1    331
===========================================================================可以看到活动路由只剩下回环。将接设备的副网卡(192.168.2x)启用,设备接在这个网卡上面,这块网卡要在后动路由表的最上面才优先
查看路由表中的活动路由(网卡全禁用)
C:\Users\chenx>route print
===========================================================================
接口列表7...00 0e c6 ca 3a 6d ......ASIX AX88179 USB 3.0 to Gigabit Ethernet Adapter1...........................Software Loopback Interface 1
===========================================================================IPv4 路由表
===========================================================================
活动路由:
网络目标        网络掩码          网关       接口   跃点数0.0.0.0          0.0.0.0      192.168.2.1    192.168.2.100    291127.0.0.0        255.0.0.0            在链路上         127.0.0.1    331127.0.0.1  255.255.255.255            在链路上         127.0.0.1    331127.255.255.255  255.255.255.255            在链路上         127.0.0.1    331192.168.2.0    255.255.255.0            在链路上     192.168.2.100    291192.168.2.100  255.255.255.255            在链路上     192.168.2.100    291192.168.2.255  255.255.255.255            在链路上     192.168.2.100    291224.0.0.0        240.0.0.0            在链路上         127.0.0.1    331224.0.0.0        240.0.0.0            在链路上     192.168.2.100    291255.255.255.255  255.255.255.255            在链路上         127.0.0.1    331255.255.255.255  255.255.255.255            在链路上     192.168.2.100    291
===========================================================================可以看到USB转网卡在活动路由表的第一位置了。将蓝牙连接的网卡启用,再看一下活动路由表
C:\Users\chenx>route print
===========================================================================
接口列表7...00 0e c6 ca 3a 6d ......ASIX AX88179 USB 3.0 to Gigabit Ethernet Adapter9...a0 a4 c5 41 5f f9 ......Bluetooth Device (Personal Area Network)1...........................Software Loopback Interface 1
===========================================================================IPv4 路由表
===========================================================================
活动路由:
网络目标        网络掩码          网关       接口   跃点数0.0.0.0          0.0.0.0      192.168.2.1    192.168.2.100    291127.0.0.0        255.0.0.0            在链路上         127.0.0.1    331127.0.0.1  255.255.255.255            在链路上         127.0.0.1    331127.255.255.255  255.255.255.255            在链路上         127.0.0.1    331192.168.2.0    255.255.255.0            在链路上     192.168.2.100    291192.168.2.100  255.255.255.255            在链路上     192.168.2.100    291192.168.2.255  255.255.255.255            在链路上     192.168.2.100    291224.0.0.0        240.0.0.0            在链路上         127.0.0.1    331224.0.0.0        240.0.0.0            在链路上     192.168.2.100    291255.255.255.255  255.255.255.255            在链路上         127.0.0.1    331255.255.255.255  255.255.255.255            在链路上     192.168.2.100    291
===========================================================================因为蓝牙网络没连接,网卡接口排在USB转网卡的后面,但是在回环前面。
活动路由没变化。将VmWare1的网卡启用,再看一下活动路由表。
C:\Users\chenx>route print
===========================================================================
接口列表23...00 50 56 c0 00 01 ......VMware Virtual Ethernet Adapter for VMnet17...00 0e c6 ca 3a 6d ......ASIX AX88179 USB 3.0 to Gigabit Ethernet Adapter9...a0 a4 c5 41 5f f9 ......Bluetooth Device (Personal Area Network)1...........................Software Loopback Interface 1
===========================================================================IPv4 路由表
===========================================================================
活动路由:
网络目标        网络掩码          网关       接口   跃点数0.0.0.0          0.0.0.0      192.168.2.1    192.168.2.100    291127.0.0.0        255.0.0.0            在链路上         127.0.0.1    331127.0.0.1  255.255.255.255            在链路上         127.0.0.1    331127.255.255.255  255.255.255.255            在链路上         127.0.0.1    331192.168.2.0    255.255.255.0            在链路上     192.168.2.100    291192.168.2.100  255.255.255.255            在链路上     192.168.2.100    291192.168.2.255  255.255.255.255            在链路上     192.168.2.100    291192.168.68.0    255.255.255.0            在链路上      192.168.68.1    291192.168.68.1  255.255.255.255            在链路上      192.168.68.1    291192.168.68.255  255.255.255.255            在链路上      192.168.68.1    291224.0.0.0        240.0.0.0            在链路上         127.0.0.1    331224.0.0.0        240.0.0.0            在链路上     192.168.2.100    291224.0.0.0        240.0.0.0            在链路上      192.168.68.1    291255.255.255.255  255.255.255.255            在链路上         127.0.0.1    331255.255.255.255  255.255.255.255            在链路上     192.168.2.100    291255.255.255.255  255.255.255.255            在链路上      192.168.68.1    291
===========================================================================可以看到接口列表中,Vmware1网卡排在USB转网卡前面。
但是活动路由中,VMware1网卡排在最后面。将VmWare2的网卡启用,再看一下活动路由表。C:\Users\chenx>route print
===========================================================================
接口列表23...00 50 56 c0 00 01 ......VMware Virtual Ethernet Adapter for VMnet15...00 50 56 c0 00 08 ......VMware Virtual Ethernet Adapter for VMnet87...00 0e c6 ca 3a 6d ......ASIX AX88179 USB 3.0 to Gigabit Ethernet Adapter9...a0 a4 c5 41 5f f9 ......Bluetooth Device (Personal Area Network)1...........................Software Loopback Interface 1
===========================================================================IPv4 路由表
===========================================================================
活动路由:
网络目标        网络掩码          网关       接口   跃点数0.0.0.0          0.0.0.0      192.168.2.1    192.168.2.100    291127.0.0.0        255.0.0.0            在链路上         127.0.0.1    331127.0.0.1  255.255.255.255            在链路上         127.0.0.1    331127.255.255.255  255.255.255.255            在链路上         127.0.0.1    331192.168.2.0    255.255.255.0            在链路上     192.168.2.100    291192.168.2.100  255.255.255.255            在链路上     192.168.2.100    291192.168.2.255  255.255.255.255            在链路上     192.168.2.100    291192.168.68.0    255.255.255.0            在链路上      192.168.68.1    291192.168.68.1  255.255.255.255            在链路上      192.168.68.1    291192.168.68.255  255.255.255.255            在链路上      192.168.68.1    291192.168.198.0    255.255.255.0            在链路上     192.168.198.1    291192.168.198.1  255.255.255.255            在链路上     192.168.198.1    291192.168.198.255  255.255.255.255            在链路上     192.168.198.1    291224.0.0.0        240.0.0.0            在链路上         127.0.0.1    331224.0.0.0        240.0.0.0            在链路上     192.168.2.100    291224.0.0.0        240.0.0.0            在链路上      192.168.68.1    291224.0.0.0        240.0.0.0            在链路上     192.168.198.1    291255.255.255.255  255.255.255.255            在链路上         127.0.0.1    331255.255.255.255  255.255.255.255            在链路上     192.168.2.100    291255.255.255.255  255.255.255.255            在链路上      192.168.68.1    291255.255.255.255  255.255.255.255            在链路上     192.168.198.1    291
===========================================================================可以看到VMware2的网卡排在最后,排在vmware1网卡的后面。将WLAN的网卡启用,再看一下活动路由表。
C:\Users\chenx>route print
===========================================================================
接口列表14...a0 a4 c5 41 5f f6 ......Microsoft Wi-Fi Direct Virtual Adapter #323...00 50 56 c0 00 01 ......VMware Virtual Ethernet Adapter for VMnet15...00 50 56 c0 00 08 ......VMware Virtual Ethernet Adapter for VMnet87...00 0e c6 ca 3a 6d ......ASIX AX88179 USB 3.0 to Gigabit Ethernet Adapter15...a0 a4 c5 41 5f f5 ......Intel(R) Dual Band Wireless-AC 82659...a0 a4 c5 41 5f f9 ......Bluetooth Device (Personal Area Network)1...........................Software Loopback Interface 1
===========================================================================IPv4 路由表
===========================================================================
活动路由:
网络目标        网络掩码          网关       接口   跃点数0.0.0.0          0.0.0.0      192.168.2.1    192.168.2.100    2910.0.0.0          0.0.0.0      192.168.1.1    192.168.1.102     35127.0.0.0        255.0.0.0            在链路上         127.0.0.1    331127.0.0.1  255.255.255.255            在链路上         127.0.0.1    331127.255.255.255  255.255.255.255            在链路上         127.0.0.1    331192.168.1.0    255.255.255.0            在链路上     192.168.1.102    291192.168.1.102  255.255.255.255            在链路上     192.168.1.102    291192.168.1.255  255.255.255.255            在链路上     192.168.1.102    291192.168.2.0    255.255.255.0            在链路上     192.168.2.100    291192.168.2.100  255.255.255.255            在链路上     192.168.2.100    291192.168.2.255  255.255.255.255            在链路上     192.168.2.100    291192.168.68.0    255.255.255.0            在链路上      192.168.68.1    291192.168.68.1  255.255.255.255            在链路上      192.168.68.1    291192.168.68.255  255.255.255.255            在链路上      192.168.68.1    291192.168.198.0    255.255.255.0            在链路上     192.168.198.1    291192.168.198.1  255.255.255.255            在链路上     192.168.198.1    291192.168.198.255  255.255.255.255            在链路上     192.168.198.1    291224.0.0.0        240.0.0.0            在链路上         127.0.0.1    331224.0.0.0        240.0.0.0            在链路上     192.168.2.100    291224.0.0.0        240.0.0.0            在链路上      192.168.68.1    291224.0.0.0        240.0.0.0            在链路上     192.168.198.1    291224.0.0.0        240.0.0.0            在链路上     192.168.1.102    291255.255.255.255  255.255.255.255            在链路上         127.0.0.1    331255.255.255.255  255.255.255.255            在链路上     192.168.2.100    291255.255.255.255  255.255.255.255            在链路上      192.168.68.1    291255.255.255.255  255.255.255.255            在链路上     192.168.198.1    291255.255.255.255  255.255.255.255            在链路上     192.168.1.102    291
===========================================================================可以看到 WLAN网卡在活动路由中,也排在USB转网卡后面。这时再运行UDP程序,可以看到有回包了。
用wireshark抓包也能证明这点(在USB转网卡那块网卡上,能看到UDP程序发出的指定UDP包和设备回包)。试验结论:
如果是做临时试验,想让哪块网卡的活动路由优先,只需要先启动那块网卡即可。
不过这么做,将临时网卡顶到最上面,能明显感觉到网页访问最开始会慢很多,应该和主网卡不在活动路由表最上面有关系。等做完试验,将主网卡顶到活动路由表最上面好些。要不访问网页时,等的有点心慌。

试验结束

为了这个试验,开始想写的UDP简版程序已经写到一半了,对于这个试验来说没大用了。已经弄清为啥UDP程序在我计算机上不好使。

可是自己点的菜,即使吃撑了,也要强忍着眼泪继续吃完。
如果不是自己点的菜,真不想继续弄。

写UDP简版程序去了:)

UDP简版程序

将测试程序写完了,以后能用上,贴在这。
程序里面加上了搜索网卡的功能,因为windows无法指定网卡发包,实现先留着。
编程环境 :vs2017 + MFC dlg
中间遇到的问题:

  • sendto, recvfrom后会有错误码,是socket建立,sendto, recvfrom函数参数写的不规矩引起的。找msdn和大家写好的UDP代码对一对,能看出区别。

// rz_searchDlg.h: 头文件
//#pragma once#include <atlconv.h>
#include <codecvt>#include <string>
using namespace std;#include <Rpc.h>
#pragma comment(lib, "Rpcrt4.lib")#include <iphlpapi.h>
#pragma comment(lib, "IPHLPAPI.lib")#pragma comment(lib, "Ws2_32.lib")#define WORKING_BUFFER_SIZE 15000
#define MAX_TRIES 3#include "CMyWrokerThread.h"
#include "C_my_row_set.h"#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))#define LINE_FOR_PRINT _T("------------------------------------------------------------")typedef enum enum_my_user_msg {msg = 0,add_net_card_list,recv_device_content,
} ENUM_MY_USER_MSG;// CRzSearchDlg 对话框
class CRzSearchDlg : public CDialog {// 构造public:CRzSearchDlg(CWnd* pParent = nullptr);    // 标准构造函数// 对话框数据
#ifdef AFX_DESIGN_TIMEenum { IDD = IDD_RZ_SEARCH_DIALOG };
#endifprotected:virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持// 实现protected:HICON m_hIcon;// 生成的消息映射函数virtual BOOL OnInitDialog();afx_msg void OnSysCommand(UINT nID, LPARAM lParam);afx_msg void OnPaint();afx_msg HCURSOR OnQueryDragIcon();afx_msg LRESULT OnUserMsg1(WPARAM wp, LPARAM lp);afx_msg void OnBnClickedButtonEnumNetCard();afx_msg void OnBnClickedButtonClearMsg();afx_msg void OnBnClickedButtonCopyMsg();afx_msg void OnBnClickedButtonSearchDevice();DECLARE_MESSAGE_MAP()public:// 线程 - 搜索网卡private:CMyWrokerThread m_Thread_query_net_card; // 查询网卡的线程CMyWrokerThread::TAG_REGISTERTHREADPROC m_Thread_query_net_card_param;public:static UINT ThreadProc_query_net_card(void* pParam);UINT       ThreadProc_query_net_card(CMyWrokerThread::TAG_REGISTERTHREADPROC* pParam);bool query_net_card(CMyWrokerThread::TAG_REGISTERTHREADPROC* pParam);SOCKET m_SendSocket = INVALID_SOCKET;// 线程 - 搜索设备private:CMyWrokerThread m_Thread_search_device;CMyWrokerThread::TAG_REGISTERTHREADPROC m_Thread_search_device_param;public:static UINT ThreadProc_search_device(void* pParam);UINT        ThreadProc_search_device(CMyWrokerThread::TAG_REGISTERTHREADPROC* pParam);bool search_device(CMyWrokerThread::TAG_REGISTERTHREADPROC* pParam);public:static const UINT USER_MSG1;static CString GUIDgen();void add_tip(CString csMsg);void add_device_recv_content(CString csMsg);void add_net_card_list(C_my_row_set* p_row_set);CEdit m_ctrl_Edit_msg;std::wstring UTF8ToUnicode(const std::string& str);std::string UnicodeToUTF8(const std::wstring& wstr);std::string my_W2A(std::wstring str);std::wstring my_A2W(std::string str);CListCtrl m_ctrl_list_net_card;CString m_str_net_card_name;CString m_str_net_card_IP;CString m_str_net_card_mac_addr;CString m_str_net_card_ID;CString m_cs_cmd_to_send;CString m_cs_device_content;CString m_cs_UDP_port;
};

// rz_searchDlg.cpp: 实现文件
//#include "pch.h"
#include "framework.h"
#include "rz_search.h"
#include "rz_searchDlg.h"
#include "afxdialogex.h"
#include "C_my_row_set.h"#ifdef _DEBUG#define new DEBUG_NEW
#endif#pragma comment(linker, "/SECTION:.shareData,RWS")
#pragma data_seg(".shareData")
HWND hInstanceWnd = NULL;
#pragma data_seg()// 用于应用程序“关于”菜单项的 CAboutDlg 对话框class CAboutDlg : public CDialogEx {public:CAboutDlg();// 对话框数据
#ifdef AFX_DESIGN_TIMEenum { IDD = IDD_ABOUTBOX };
#endifprotected:virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持// 实现protected:DECLARE_MESSAGE_MAP()
};CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{}void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);
}BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()// CRzSearchDlg 对话框const UINT CRzSearchDlg::USER_MSG1 = ::RegisterWindowMessage(GUIDgen());CString CRzSearchDlg::GUIDgen()
{GUID guid;HRESULT hRc = CoCreateGuid(&guid);if (S_OK != hRc) {AfxMessageBox(_T("Error: CoCreateGuid"));}RPC_WSTR str = NULL;UuidToString((UUID*)&guid, &str);// CString unique = ((LPTSTR)str);CString unique = ((LPTSTR)str);RpcStringFree(&str);//unique.Replace(_T("-"), _T("_"));CString csMyUUID;csMyUUID.Format(_T("%s-{%s}"), _T("USER_MSG1"), unique);csMyUUID.MakeUpper();return csMyUUID;
}CRzSearchDlg::CRzSearchDlg(CWnd* pParent /*=nullptr*/): CDialog(IDD_RZ_SEARCH_DIALOG, pParent), m_cs_cmd_to_send(_T("")), m_cs_device_content(_T("")), m_cs_UDP_port(_T(""))
{m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}void CRzSearchDlg::DoDataExchange(CDataExchange* pDX)
{CDialog::DoDataExchange(pDX);DDX_Control(pDX, IDC_EDIT_MSG, m_ctrl_Edit_msg);DDX_Control(pDX, IDC_LIST_NET_CARD, m_ctrl_list_net_card);DDX_Text(pDX, IDC_EDIT_UDP_CMD_TO_SEND, m_cs_cmd_to_send);DDX_Text(pDX, IDC_EDIT_DEVICE_CONTENT, m_cs_device_content);DDX_Text(pDX, IDC_EDIT_UDP_PORT, m_cs_UDP_port);
}BEGIN_MESSAGE_MAP(CRzSearchDlg, CDialog)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_BUTTON_ENUM_NET_CARD, &CRzSearchDlg::OnBnClickedButtonEnumNetCard)ON_REGISTERED_MESSAGE(USER_MSG1, OnUserMsg1)ON_BN_CLICKED(IDC_BUTTON_CLEAR_MSG, &CRzSearchDlg::OnBnClickedButtonClearMsg)ON_BN_CLICKED(IDC_BUTTON_COPY_MSG, &CRzSearchDlg::OnBnClickedButtonCopyMsg)ON_BN_CLICKED(IDC_BUTTON_SEARCH_DEVICE, &CRzSearchDlg::OnBnClickedButtonSearchDevice)
END_MESSAGE_MAP()void CRzSearchDlg::add_tip(CString csMsg)
{CString* pcsMsg = new CString;*pcsMsg = csMsg;::PostMessage(this->m_hWnd, USER_MSG1, ENUM_MY_USER_MSG::msg, (LPARAM)(pcsMsg));
}void CRzSearchDlg::add_device_recv_content(CString csMsg)
{CString* pcsMsg = new CString;*pcsMsg = csMsg;::PostMessage(this->m_hWnd, USER_MSG1, ENUM_MY_USER_MSG::recv_device_content, (LPARAM)(pcsMsg));
}void CRzSearchDlg::add_net_card_list(C_my_row_set* p_row_set)
{::PostMessage(this->m_hWnd, USER_MSG1, ENUM_MY_USER_MSG::add_net_card_list, (LPARAM)(p_row_set));
}// CRzSearchDlg 消息处理程序
LRESULT CRzSearchDlg::OnUserMsg1(WPARAM wp, LPARAM lp)
{LRESULT lRc = S_OK;CString csMsg_src;CString csMsg_dst;CTime time;CString str_time;int len = 0;int i_type = (INT)wp;int i = 0;int i_cnt = 0;int j = 0;int j_cnt = 0;C_my_row row;C_my_row_set* p_rowset = NULL;C_my_key_val key_val;int nRow = 0;if (lp) {if (ENUM_MY_USER_MSG::msg == i_type) {CString* pMsg = (CString*)lp;csMsg_src = *pMsg;delete (pMsg);pMsg = NULL;m_ctrl_Edit_msg.GetWindowText(csMsg_dst);len = m_ctrl_Edit_msg.GetWindowTextLength();if (len >= (1024 * 63)) {csMsg_dst.Empty();m_ctrl_Edit_msg.GetWindowText(csMsg_dst);}time = CTime::GetCurrentTime();str_time = time.Format(_T("%Y/%m/%d %H:%M:%S"));csMsg_dst.Empty();csMsg_dst += str_time;csMsg_dst += " ";csMsg_dst += csMsg_src;csMsg_dst += _T("\r\n");m_ctrl_Edit_msg.SetSel(len, len); // 将插入光标放在最后m_ctrl_Edit_msg.ReplaceSel(csMsg_dst);} else if (ENUM_MY_USER_MSG::add_net_card_list == i_type) {p_rowset = (C_my_row_set*)lp;if (NULL != p_rowset) {i_cnt = (int)p_rowset->m_list.GetCount();for (i = 0; i < i_cnt; i++) {row = p_rowset->m_list.GetAt(p_rowset->m_list.FindIndex(i));// j_cnt = row.m_list.GetCount();key_val = row.m_list.GetAt(row.m_list.FindIndex(2));nRow = m_ctrl_list_net_card.InsertItem(0, key_val.m_cs_val.GetString());//插入行key_val = row.m_list.GetAt(row.m_list.FindIndex(1));m_ctrl_list_net_card.SetItemText(nRow, 1, key_val.m_cs_val.GetString());//设置数据key_val = row.m_list.GetAt(row.m_list.FindIndex(3));m_ctrl_list_net_card.SetItemText(nRow, 2, key_val.m_cs_val.GetString());//设置数据key_val = row.m_list.GetAt(row.m_list.FindIndex(0));m_ctrl_list_net_card.SetItemText(nRow, 3, key_val.m_cs_val.GetString());//设置数据}p_rowset->clear();delete p_rowset;p_rowset = NULL;}} else if (ENUM_MY_USER_MSG::recv_device_content == i_type) {CString* pMsg = (CString*)lp;csMsg_src = *pMsg;delete (pMsg);pMsg = NULL;this->UpdateData(TRUE);m_cs_device_content = csMsg_src;this->UpdateData(FALSE);}}return lRc;
}BOOL CRzSearchDlg::OnInitDialog()
{CDialog::OnInitDialog();hInstanceWnd = m_hWnd;// 将“关于...”菜单项添加到系统菜单中。// IDM_ABOUTBOX 必须在系统命令范围内。ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX < 0xF000);CMenu* pSysMenu = GetSystemMenu(FALSE);if (pSysMenu != nullptr) {BOOL bNameValid;CString strAboutMenu;bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);ASSERT(bNameValid);if (!strAboutMenu.IsEmpty()) {pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);}}// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动//  执行此操作SetIcon(m_hIcon, TRUE);         // 设置大图标SetIcon(m_hIcon, FALSE);        // 设置小图标// TODO: 在此添加额外的初始化代码LONG lStyle;lStyle = GetWindowLong(m_ctrl_list_net_card.m_hWnd, GWL_STYLE);//获取当前窗口stylelStyle &= ~LVS_TYPEMASK; //清除显示方式位lStyle |= LVS_REPORT; //设置styleSetWindowLong(m_ctrl_list_net_card.m_hWnd, GWL_STYLE, lStyle);//设置styleDWORD dwStyle = m_ctrl_list_net_card.GetExtendedStyle();dwStyle |= LVS_EX_FULLROWSELECT;//选中某行使整行高亮(只适用与report风格的listctrl)dwStyle |= LVS_SHOWSELALWAYS;dwStyle |= LVS_EX_GRIDLINES;//网格线(只适用与report风格的listctrl)m_ctrl_list_net_card.SetExtendedStyle(dwStyle); //设置扩展风格m_ctrl_list_net_card.InsertColumn(0, _T("网卡名称"), LVCFMT_CENTER, 200/*列宽*/, 0);m_ctrl_list_net_card.InsertColumn(1, _T("网卡IP"), LVCFMT_CENTER, 200, 1);m_ctrl_list_net_card.InsertColumn(2, _T("网卡MAC地址"), LVCFMT_CENTER, 200, 1);m_ctrl_list_net_card.InsertColumn(3, _T("网卡实际名称"), LVCFMT_CENTER, 400, 2);this->UpdateData(TRUE);m_cs_UDP_port = _T("12345"); // defualt UDP portm_cs_cmd_to_send = _T("cmd_query"); // default cmd to devicethis->UpdateData(FALSE);return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}void CRzSearchDlg::OnSysCommand(UINT nID, LPARAM lParam)
{if ((nID & 0xFFF0) == IDM_ABOUTBOX) {CAboutDlg dlgAbout;dlgAbout.DoModal();} else {CDialog::OnSysCommand(nID, lParam);}
}// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。void CRzSearchDlg::OnPaint()
{if (IsIconic()) {CPaintDC dc(this); // 用于绘制的设备上下文SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);// 使图标在工作区矩形中居中int cxIcon = GetSystemMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIcon + 1) / 2;// 绘制图标dc.DrawIcon(x, y, m_hIcon);} else {CDialog::OnPaint();}
}//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CRzSearchDlg::OnQueryDragIcon()
{return static_cast<HCURSOR>(m_hIcon);
}void CRzSearchDlg::OnBnClickedButtonEnumNetCard()
{// TODO: 在此添加控件通知处理程序代码add_tip(_T("按钮被点击 - 枚举网卡列表"));do {if (m_Thread_query_net_card.is_running()) {add_tip(_T("任务(枚举网卡列表)进行中..., 请稍候"));break;}m_ctrl_list_net_card.DeleteAllItems();// 任务执行要放到线程中去做,否则UI卡住m_Thread_query_net_card_param.pOwner = this;m_Thread_query_net_card_param.pUserData = &m_Thread_query_net_card_param;m_Thread_query_net_card_param.pfnThreadProc = ThreadProc_query_net_card;m_Thread_query_net_card.RegisterThreadProc(&m_Thread_query_net_card_param);// 启动线程m_Thread_query_net_card.Start();} while (0);
}UINT CRzSearchDlg::ThreadProc_query_net_card(void* pParam)
{CMyWrokerThread::TAG_REGISTERTHREADPROC* pThreadInfo = NULL;CRzSearchDlg* pMe = NULL;if (NULL == pParam) {return -1;}pThreadInfo = (CMyWrokerThread::TAG_REGISTERTHREADPROC*)pParam;if (NULL == pThreadInfo->pOwner) {return -1;}pMe = (CRzSearchDlg*)pThreadInfo->pOwner;return pMe->ThreadProc_query_net_card((CMyWrokerThread::TAG_REGISTERTHREADPROC*)pParam);
}UINT CRzSearchDlg::ThreadProc_query_net_card(CMyWrokerThread::TAG_REGISTERTHREADPROC* pParam)
{add_tip(_T("枚举网卡 - 开始"));add_tip(_T("枚举网卡 ..."));query_net_card(pParam);add_tip(_T("枚举网卡 - 结束"));return 0;
}bool CRzSearchDlg::query_net_card(CMyWrokerThread::TAG_REGISTERTHREADPROC* pParam)
{// https://docs.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getadaptersaddresses// https://blog.csdn.net/gaiazhang/article/details/9037139CHAR szIP[130] = { _T('\0') };CString csMsg;CString csTmp1;CString csTmp2;C_my_row_set* p_row_set = new C_my_row_set;C_my_row row_set;C_my_key_val key_val;/* Declare and initialize variables */DWORD dwSize = 0;DWORD dwRetVal = 0;unsigned int i = 0;// Set the flags to pass to GetAdaptersAddressesULONG flags = GAA_FLAG_INCLUDE_PREFIX;// default to unspecified address family (both)ULONG family = AF_UNSPEC;LPVOID lpMsgBuf = NULL;PIP_ADAPTER_ADDRESSES pAddresses = NULL;ULONG outBufLen = 0;ULONG Iterations = 0;PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL;PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL;IP_ADAPTER_DNS_SERVER_ADDRESS* pDnServer = NULL;IP_ADAPTER_PREFIX* pPrefix = NULL;family = AF_INET;add_tip(_T("get IPV4 net card info"));outBufLen = /*WORKING_BUFFER_SIZE*/ sizeof(IP_ADAPTER_ADDRESSES) * 100;bool b_rc = false;do {do {pAddresses = (IP_ADAPTER_ADDRESSES*)MALLOC(outBufLen);if (pAddresses == NULL) {add_tip(_T("Memory allocation failed for IP_ADAPTER_ADDRESSES struct"));break;}dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);if (dwRetVal == ERROR_BUFFER_OVERFLOW) {add_tip(_T("retry get net card info"));FREE(pAddresses);pAddresses = NULL;} else {break;}Iterations++;} while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES));if (NULL == pAddresses) {add_tip(_T("can't get net card info"));break;}if (dwRetVal == NO_ERROR) {// If successful, output some information from the data we receivedpCurrAddresses = pAddresses;while (pCurrAddresses) {add_tip(LINE_FOR_PRINT);row_set.clear();csMsg.Format(_T("\tLength of the IP_ADAPTER_ADDRESS struct: %ld"), pCurrAddresses->Length);add_tip(csMsg);csMsg.Format(_T("\tIfIndex (IPv4 interface): %u"), pCurrAddresses->IfIndex);add_tip(csMsg);csMsg.Format(_T("\tAdapter name: %s"), this->my_A2W(pCurrAddresses->AdapterName).c_str());add_tip(csMsg);key_val.m_cs_key = _T("Adapter_name");key_val.m_cs_val = this->my_A2W(pCurrAddresses->AdapterName).c_str();row_set.m_list.AddTail(key_val);pUnicast = pCurrAddresses->FirstUnicastAddress;if (pUnicast != NULL) {for (i = 0; pUnicast != NULL; i++) {// 只找第一个IPif (0 == i) {csTmp2.Empty();szIP[0] = '\0';if (AF_INET == pUnicast->Address.lpSockaddr->sa_family) {// IPV4 地址,使用 IPV4 转换inet_ntop(PF_INET, &((sockaddr_in*)pUnicast->Address.lpSockaddr)->sin_addr, szIP, sizeof(szIP));csTmp2 = my_A2W(string(szIP)).c_str();} else if (AF_INET6 == pUnicast->Address.lpSockaddr->sa_family) {// IPV6 地址,使用 IPV6 转换inet_ntop(PF_INET6, &((sockaddr_in6*)pUnicast->Address.lpSockaddr)->sin6_addr, szIP, sizeof(szIP));csTmp2 = my_A2W(string(szIP)).c_str();}key_val.m_cs_key = _T("First_IP");key_val.m_cs_val = csTmp2;row_set.m_list.AddTail(key_val);}pUnicast = pUnicast->Next;}csMsg.Format(_T("\tNumber of Unicast Addresses: %d"), i);add_tip(csMsg);} else {csMsg.Format(_T("\tNo Unicast Addresses"));add_tip(csMsg);}pAnycast = pCurrAddresses->FirstAnycastAddress;if (pAnycast) {for (i = 0; pAnycast != NULL; i++) {pAnycast = pAnycast->Next;}csMsg.Format(_T("\tNumber of Anycast Addresses: %d"), i);add_tip(csMsg);} else {csMsg.Format(_T("\tNo Anycast Addresses"));add_tip(csMsg);}pMulticast = pCurrAddresses->FirstMulticastAddress;if (pMulticast) {for (i = 0; pMulticast != NULL; i++) {pMulticast = pMulticast->Next;}csMsg.Format(_T("\tNumber of Multicast Addresses: %d"), i);add_tip(csMsg);} else {csMsg.Format(_T("\tNo Multicast Addresses"));add_tip(csMsg);}pDnServer = pCurrAddresses->FirstDnsServerAddress;if (pDnServer) {for (i = 0; pDnServer != NULL; i++) {pDnServer = pDnServer->Next;}csMsg.Format(_T("\tNumber of DNS Server Addresses: %d"), i);add_tip(csMsg);} else {csMsg.Format(_T("\tNo DNS Server Addresses"));add_tip(csMsg);}csMsg.Format(_T("\tDNS Suffix: %wS"), pCurrAddresses->DnsSuffix);add_tip(csMsg);csMsg.Format(_T("\tDescription: %wS"), pCurrAddresses->Description);add_tip(csMsg);csMsg.Format(_T("\tFriendly name: %wS"), pCurrAddresses->FriendlyName);add_tip(csMsg);key_val.m_cs_key = _T("Friendly_name");key_val.m_cs_val = pCurrAddresses->FriendlyName;row_set.m_list.AddTail(key_val);if (pCurrAddresses->PhysicalAddressLength != 0) {csTmp2.Empty();csMsg.Format(_T("\tPhysical address: "));for (i = 0; i < (int)pCurrAddresses->PhysicalAddressLength;i++) {if (i == (pCurrAddresses->PhysicalAddressLength - 1)) {csTmp1.Format(_T("%.2X"), (int)pCurrAddresses->PhysicalAddress[i]);} else {csTmp1.Format(_T("%.2X-"), (int)pCurrAddresses->PhysicalAddress[i]);}csMsg += csTmp1;csTmp2 += csTmp1;}key_val.m_cs_key = _T("Physical_address");key_val.m_cs_val = csTmp2;row_set.m_list.AddTail(key_val);add_tip(csMsg);} else {key_val.m_cs_key = _T("Physical_address");key_val.m_cs_val = _T("");row_set.m_list.AddTail(key_val);}csMsg.Format(_T("\tFlags: %ld"), pCurrAddresses->Flags);add_tip(csMsg);csMsg.Format(_T("\tMtu: %lu"), pCurrAddresses->Mtu);add_tip(csMsg);csMsg.Format(_T("\tIfType: %ld"), pCurrAddresses->IfType);add_tip(csMsg);csMsg.Format(_T("\tOperStatus: %ld"), pCurrAddresses->OperStatus);add_tip(csMsg);csMsg.Format(_T("\tIpv6IfIndex (IPv6 interface): %u"), pCurrAddresses->Ipv6IfIndex);add_tip(csMsg);csMsg.Format(_T("\tZoneIndices (hex): "));for (i = 0; i < 16; i++) {csTmp1.Format(_T("%2.2X"), pCurrAddresses->ZoneIndices[i]);if (i != (16 - 1)) {csTmp1 += _T(" ");}csMsg += csTmp1;}add_tip(csMsg);csMsg.Format(_T("\tTransmit link speed: %I64u"), pCurrAddresses->TransmitLinkSpeed);add_tip(csMsg);csMsg.Format(_T("\tReceive link speed: %I64u"), pCurrAddresses->ReceiveLinkSpeed);add_tip(csMsg);pPrefix = pCurrAddresses->FirstPrefix;if (pPrefix) {for (i = 0; pPrefix != NULL; i++) {pPrefix = pPrefix->Next;}csMsg.Format(_T("\tNumber of IP Adapter Prefix entries: %d"), i);add_tip(csMsg);} else {csMsg.Format(_T("\tNumber of IP Adapter Prefix entries: 0"));add_tip(csMsg);}p_row_set->m_list.AddTail(row_set);pCurrAddresses = pCurrAddresses->Next;}} else {if (dwRetVal == ERROR_NO_DATA) {} else {if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,NULL, dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),// Default language(LPTSTR)& lpMsgBuf, 0, NULL)) {add_tip((LPTSTR)lpMsgBuf);LocalFree(lpMsgBuf);}}}b_rc = true;} while (0);if (b_rc) {add_net_card_list(p_row_set);} else {p_row_set->clear();delete p_row_set;p_row_set = NULL;}if (pAddresses) {FREE(pAddresses);pAddresses = NULL;}return b_rc;
}// https://blog.csdn.net/FlushHip/article/details/82836867
std::wstring CRzSearchDlg::UTF8ToUnicode(const std::string& str)
{std::wstring ret;try {std::wstring_convert< std::codecvt_utf8<wchar_t> > wcv;ret = wcv.from_bytes(str);} catch (const std::exception& e) {// std::cerr << e.what() << std::endl;e.what();}return ret;
}std::string CRzSearchDlg::UnicodeToUTF8(const std::wstring& wstr)
{std::string ret;try {std::wstring_convert< std::codecvt_utf8<wchar_t> > wcv;ret = wcv.to_bytes(wstr);} catch (const std::exception& e) {// std::cerr << e.what() << std::endl;e.what();}return ret;
}std::string CRzSearchDlg::my_W2A(std::wstring str)
{USES_CONVERSION;std::string str_rc = W2A(str.c_str());return str_rc;
}std::wstring CRzSearchDlg::my_A2W(std::string str)
{USES_CONVERSION;std::wstring str_rc = A2W(str.c_str());return str_rc;
}void CRzSearchDlg::OnBnClickedButtonClearMsg()
{// TODO: 在此添加控件通知处理程序代码this->m_ctrl_Edit_msg.SetWindowTextW(_T(""));
}void CRzSearchDlg::OnBnClickedButtonCopyMsg()
{// TODO: 在此添加控件通知处理程序代码int i_text_cb_len = 0;CString csMsg;if (OpenClipboard()) {HGLOBAL clipbuffer;char* buffer;EmptyClipboard();i_text_cb_len = m_ctrl_Edit_msg.GetWindowTextLengthW() * sizeof(TCHAR);m_ctrl_Edit_msg.GetWindowTextW(csMsg);clipbuffer = GlobalAlloc(GMEM_DDESHARE, i_text_cb_len + 1);buffer = (char*)GlobalLock(clipbuffer);strcpy(buffer, my_W2A(csMsg.GetString()).c_str());GlobalUnlock(clipbuffer);SetClipboardData(CF_TEXT, clipbuffer);CloseClipboard();}
}void CRzSearchDlg::OnBnClickedButtonSearchDevice()
{// TODO: 在此添加控件通知处理程序代码POSITION pos = NULL;int iRow_index = 0;CString csMsg;do {if (m_Thread_search_device.is_running()) {add_tip(_T("任务(枚举网卡列表)进行中..., 请稍候"));break;}this->UpdateData(TRUE);if (m_cs_cmd_to_send.GetLength() <= 0) {csMsg.Format(_T("请填写要发给设备的UDP命令!"));add_tip(csMsg);break;}if (m_cs_UDP_port.GetLength() <= 0) {csMsg.Format(_T("请填写要发给设备的UDP端口!"));add_tip(csMsg);break;}this->m_cs_device_content.Empty();this->UpdateData(FALSE);pos = m_ctrl_list_net_card.GetFirstSelectedItemPosition();if (NULL != pos) {iRow_index = m_ctrl_list_net_card.GetNextSelectedItem(pos);m_str_net_card_name = m_ctrl_list_net_card.GetItemText(iRow_index, 0);m_str_net_card_IP = m_ctrl_list_net_card.GetItemText(iRow_index, 1);m_str_net_card_mac_addr = m_ctrl_list_net_card.GetItemText(iRow_index, 2);m_str_net_card_ID = m_ctrl_list_net_card.GetItemText(iRow_index, 3);csMsg.Format(_T("目标网卡 - 名称 = [%s]"), m_str_net_card_name);add_tip(csMsg);csMsg.Format(_T("目标网卡 - IP = [%s]"), m_str_net_card_IP);add_tip(csMsg);csMsg.Format(_T("目标网卡 - MAC地址 = [%s]"), m_str_net_card_mac_addr);add_tip(csMsg);csMsg.Format(_T("目标网卡 - UID = [%s]"), m_str_net_card_ID);add_tip(csMsg);csMsg.Format(_T("目标网卡 - 命令 = [%s]"), m_cs_cmd_to_send);add_tip(csMsg);// 任务执行要放到线程中去做,否则UI卡住m_Thread_search_device_param.pOwner = this;m_Thread_search_device_param.pUserData = &m_Thread_search_device_param;m_Thread_search_device_param.pfnThreadProc = ThreadProc_search_device;m_Thread_search_device.RegisterThreadProc(&m_Thread_search_device_param);// 启动线程m_Thread_search_device.Start();} else {add_tip(_T("请先选择要广播的网卡"));}} while (0);
}UINT CRzSearchDlg::ThreadProc_search_device(void* pParam)
{CMyWrokerThread::TAG_REGISTERTHREADPROC* pThreadInfo = NULL;CRzSearchDlg* pMe = NULL;if (NULL == pParam) {return -1;}pThreadInfo = (CMyWrokerThread::TAG_REGISTERTHREADPROC*)pParam;if (NULL == pThreadInfo->pOwner) {return -1;}pMe = (CRzSearchDlg*)pThreadInfo->pOwner;return pMe->ThreadProc_search_device((CMyWrokerThread::TAG_REGISTERTHREADPROC*)pParam);
}UINT CRzSearchDlg::ThreadProc_search_device(CMyWrokerThread::TAG_REGISTERTHREADPROC* pParam)
{add_tip(_T("搜索设备 - 开始"));add_tip(_T("搜索设备 ..."));search_device(pParam);add_tip(_T("搜索设备 - 结束"));return 0;
}bool CRzSearchDlg::search_device(CMyWrokerThread::TAG_REGISTERTHREADPROC* pParam)
{// https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-sendto// https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recvfrombool b_socket_init_ok = false;bool b_rc = false;int iResult;WSADATA wsaData;sockaddr_in RecvAddr;unsigned short Port = _wtoi(m_cs_UDP_port.GetString())/*65011*/;char SendBuf[1024 * 4];int BufLen = sizeof(SendBuf);CString csMsg;CString csTmp1;std::string strTmp;int i_rc = 0;char RecvBuf[1024 * 4];int RecvLen = sizeof(RecvBuf);int ilen_SOCKADDR = 0;do {//----------------------// Initialize WinsockiResult = WSAStartup(MAKEWORD(2, 2), &wsaData);if (iResult != NO_ERROR) {csMsg.Format(_T("WSAStartup failed with error: %d"), iResult);add_tip(csMsg);break;}b_socket_init_ok = true;//---------------------------------------------// Create a socket for sending datam_SendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);if (INVALID_SOCKET == m_SendSocket) {csMsg.Format(_T("socket failed with error: %ld"), WSAGetLastError());add_tip(csMsg);break;}if (true) {const char opt = 1; // char or int all ok//设置该套接字为广播类型,int cb = 0;cb = setsockopt(m_SendSocket, SOL_SOCKET, SO_BROADCAST, (const char*)&opt, sizeof(opt));if (cb < 0) {csMsg.Format(_T("set socket error..."));add_tip(csMsg);break;}}memset(&RecvAddr, 0, sizeof(RecvAddr));RecvAddr.sin_family = AF_INET;RecvAddr.sin_port = htons(Port);RecvAddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);//---------------------------------------------// Send a datagram to the receivercsMsg.Format(_T("Sending a datagram to the receiver..."));add_tip(csMsg);// wireshark 显示过滤器// udp.port == 12345// 可以看到在回环网卡和WLAN上有发包do {strTmp = my_W2A(m_cs_cmd_to_send.GetString());BufLen = (int)strTmp.length();memcpy(SendBuf, strTmp.data(), BufLen);iResult = sendto(m_SendSocket,SendBuf, BufLen, 0, (SOCKADDR*)& RecvAddr, sizeof(RecvAddr));if (iResult == SOCKET_ERROR) {csMsg.Format(_T("sendto failed with error: %d"), WSAGetLastError());add_tip(csMsg);break;}memset(RecvBuf, 0, sizeof(RecvBuf));RecvLen = 512; // okilen_SOCKADDR = sizeof(RecvAddr); // okSleep(10);iResult = recvfrom(m_SendSocket, RecvBuf, RecvLen, 0, (SOCKADDR*)&RecvAddr, &ilen_SOCKADDR);if (iResult == SOCKET_ERROR) {csMsg.Format(_T("recvfrom failed with error: %d"), WSAGetLastError());add_tip(csMsg);break;}csMsg.Format(_T("%s"), my_A2W(RecvBuf).c_str());this->add_device_recv_content(csMsg);} while (0);b_rc = true;} while (0);//---------------------------------------------// Clean up and quit.csMsg.Format(_T("Exit search"));add_tip(csMsg);//---------------------------------------------// When the application is finished sending, close the socket.csMsg.Format(_T("Finished sending. Closing socket."));add_tip(csMsg);if (INVALID_SOCKET != m_SendSocket) {closesocket(m_SendSocket);m_SendSocket = INVALID_SOCKET;}if (b_socket_init_ok) {b_socket_init_ok = false;WSACleanup();}return b_rc;
}

windows中手工调整活动路由表的简单方法相关推荐

  1. python字符计数怎样去除空格_去除python中的字符串空格的简单方法

    python编程中,我们在修改代码,遇到空格很多的情况下,我们要删除空格.本文小编整理了三种字符串去除空格的方法: 方法一:使用字符串函数replace,去除全部空格. 实例: >>> ...

  2. java中使用配置文件_Java中使用Properties配置文件的简单方法

    Java中使用Properties配置文件的简单方法 properties Properties文件是java中的一种配置文件,文件后缀为".properties",文件的内容格式 ...

  3. 【ES】CURL在windows中对ElasticSearch的一些简单的操作

    上一节说了CURL在windows中的安装方式,现在就简单的记录下CURL在windows中对ElasticSearch的一些简单的操作 直接上操作命令 首先我们打开cmd命令行 输入curl -he ...

  4. 服务器显示隐藏任务,在Windows 10中隐藏任务栏的简单方法

    作为Windows用户,您可能已经注意到任务栏总是显示在屏幕上.对于某些用户来说,这可能是最令人欣慰的事情.但是,对于其余用户而言,全屏显示的任务栏很烦人.在这些人中,确实有一些人不知道可以随时隐藏它 ...

  5. 在Windows 7、8、10、11中恢复Word文件的简单方法

    "急急急!我使用快捷键"Shift + Delete"从我的电脑中删除了一些Word文件.但是我现在急需找回删除的Word文件,但我在回收站中找不到它们,并且我以前也没有 ...

  6. 将品牌机预装的 Windows 7 家庭版升级为 Windows 7 旗舰版的超级简单方法

    在 Windows 7 诸版本中,旗舰版是功能最全的版本.目前"电脑城"主流品牌机之所以预装 Windows 7 家庭版而不是旗舰版,究其原因非常简单:完全基于最大限度降低成本和抢 ...

  7. figma设计_一种在Figma中跟踪设计迭代的简单方法

    figma设计 As designers, telling a good story is always part of the job. A great story engages the clie ...

  8. Visual Studio 2013中引入Web Service的简单方法visual studio 引用 wsdl

    http://blog.csdn.net/wangzhongbo_24/article/details/49954191 Web Service有三种表示方式 三种方式分别为WSDL.Endpoint ...

  9. 用uefi安装linux系统安装win7系统分区,UEFI启动 + GPT 安装 Windows + Ubunut 16.10双系统 简单方法...

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 此方法在 Windows 7 和 Lubuntu 16.10 下验证通过,电脑主板是微星Z97 Gaming 7. UEFI+GPT 装 win/linu ...

最新文章

  1. 计算机语言中索引什么意思,算法索引
  2. springboot2新版springcloud微服务,带你了解不一样的springboot2
  3. 一天搞定CSS:文本text--05
  4. 在winform嵌入外部应用程序
  5. ios开发跳转safari_阻止iOS Web APP中点击链接跳转到Safari 浏览器新标签页
  6. 简述vue-router实现原理
  7. 文件服务器存储解决方案探索
  8. linux tar文件夹打包不包含目录,tar打包如何不打包某一个文件夹(排除某些文件夹)...
  9. NXP:I2C总线技术规范和用户手册(中文版)(一)
  10. Word中如何删除某一页的页眉与页眉中的横线
  11. 樊登读书赋能读后感_樊登读书会本周末视频解读新书:《赋能》拉开你与别人的差距,决定你人生的高度...
  12. 深度学习系列笔记之统计基础
  13. 面试 -- 操作系统与计算机网络
  14. 求图纸形心的数据预处理与形心计算代码:输入多个矩形的坐标和长度宽度,计算它们的形心坐标
  15. iphone原彩显示对眼睛好吗_iphone的原彩显示有什么用吗
  16. 一文读懂MES是什么,浅谈EMS系统带给企业的好处
  17. 碧桂园博智林机器人 一面面试题
  18. Web Workers RPC
  19. 软件测试培训哪里好?主要还是看需要提升班和小白班
  20. ThoughtWorks: 精益企业之道需新型企业治理模式

热门文章

  1. Matlab GUI界面编程小白学习笔记
  2. 关于win7一些注册表操作
  3. Maven 生成打包可执行jar包
  4. 用Python将输入1-99999的数转化为大写中文形式
  5. vue3使用富文本编辑器vueQuill
  6. 光通信器件与系统(西交大朱京平笔记) -2-4 半导体激光器的工作特性
  7. 狂潮微课小红书推广引流教程
  8. 人岗智能匹配系统(中)
  9. 容联腾讯云强强联手 领跑企业通讯云服务
  10. easyui datebox 时间格式化(Mon Jan 02 00:00:00 cst 2017)