当前位置:首页 > 芯闻号 > 充电吧
[导读]【1】工具介绍:用到的工具:VS2015 语言:C/C++ 需要系统提供的动态链接库:1、 sporder.dll    //很多系统不自带着个dll,导致编译时缺少dll无法编译. (发布时必须将此

【1】工具介绍:


用到的工具:VS2015
语言:C/C++
需要系统提供的动态链接库:1、 sporder.dll    //很多系统不自带着个dll,导致编译时缺少dll无法编译. (发布时必须将此dll放到程序目录)
本人只提供:   WIN7 64位的sporder.dll :http://download.csdn.net/download/aaron133/10153240
               其他系统自行网上下载.

安装、移除LSP、编写分层提供者DLL、测试程序的源码:(申明:本人只在Win7 32/64位 和 Win10 64测试过)
http://download.csdn.net/download/aaron133/10152873 
(除了文章中的源码之外,包含了测试程序的源码)


【2】编写LSP分层服务提供者需知的概念:


1、先看我写的SPI接口的概念:http://blog.csdn.net/aaron133/article/details/78005779

2、本章就是介绍安装SPI的分层协议提供者(LSP),即第三方系统网络组件。

3、当Windows程序想要使用网络时,必须加载SPI的基础提供者(TCP、UDP、原始)才能进行网络通讯。

4、安装LSP分层服务提供者就是写一个DLL,让网络程序先加载进去调用,然后再我们的DLL内,再调用基础服务提供者,进行网络通讯,所以在这过程中,我们可以对系统上所有使用特定协议的网络程序,在用户模式下进行Winsock API调用监控,HOOK拦截,甚至利用LSP注入DLL。

5、LSP一般是对网络进行更高级的通讯服务管理、过滤,黑客常用它来进行浏览器劫持、监控用户信息等等.

6、360所谓的修复LSP或CMD的netsh winsock reset命令,就是清除第三方的LSP提供者,并清除它的DLL,留下系统的基础服务提供者.


【3】不能拦截的Winsock API函数:


1、htonl,htons仅在ws2_32.dll中实现.
2、inet_addr,inet_ntoa,gethostname,WSACreateEvent,WSACloseEvent等等都不在SPI中.

3、如果程序直接使用传输驱动接口(TDI)进行TCP/IP发送数据包,那么拦截不了.

4、所以在用户模式下,使用LSP过滤网络封包是一个很好的选择.

【4】LSP分层服务提供者的编写:(DLL)


一、简述:

1、编写LSP提供者就是写一个DLL.

2、WSPStartup是LSP必须导出的函数.

3、加载下层提供者的DLL,并调用它的初始化WSPStartup是LSP必须做的事情.

4、拦截API函数就是将下层提供者(基础协议提供者)的函数地址记录下来,将我们自定义的函数地址替换上去,执行到如send时就会先调用我们的自定义函数,再由我们的自定义函数,考虑要不要调用真正的send.


二、开始编写LSP分层服务提供者的DLL:


【开始编写】

1、步骤 :创建Win32程序     -->     DLL开发

2、新建一个.def文件:

EXPORTS
WSPStartup      @2


【代码步骤分析】

1、网络程序加载LSP分层服务提供者的DLL,并调用了DLL里的WSPStartup初始化函数.

2、在LSP的WSPStartup函数中,加载它的下层服务提供者的DLL,并调用它的WSPStartup初始化函数.

3、对下层提供者的函数表地址进行修改,修改感兴趣的网络函数指向我们的自定义函数,进行拦截、监视Winsock API.

4、下面的例子中拦截了connect函数、sendto函数.


头文件:       //在讲解SPI篇的时候,用到的函数,用于遍历系统所有协议,包括分层协议

#include#include#includeLPWSAPROTOCOL_INFOW GetProvider(LPINT lpnTotalProtocols)
{//遍历所有协议
int nError = 0;
DWORD dwSize = 0;
LPWSAPROTOCOL_INFOW pProtoInfo = NULL;
if (WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError) == SOCKET_ERROR)
{
if (nError != WSAENOBUFS)
return NULL;
}
pProtoInfo = (LPWSAPROTOCOL_INFOW)new WSAPROTOCOL_INFOW[dwSize / sizeof(WSAPROTOCOL_INFOW)];
if (!pProtoInfo)
return NULL;
ZeroMemory(pProtoInfo, dwSize);
*lpnTotalProtocols = WSAEnumProtocols(NULL, pProtoInfo, &dwSize);
return pProtoInfo;
}
void FreeProvider(LPWSAPROTOCOL_INFOW pProtoInfo)
{
delete[] pProtoInfo;
}

源文件:

WSPPROC_TABLE g_NextProcTable;  //下层提供者的函数表        全局
//LSP的初始化函数(唯一的导出函数)
int WSPAPI WSPStartup(
WORD wVersionRequested,                          //用户程序加载套接字库的版本号(in)
LPWSPDATA lpWSPData,                               //用于取得Winsock服务的详细信息
LPWSAPROTOCOL_INFO lpProtocolInfo,   //指定想得到的协议的特征
WSPUPCALLTABLE UpcallTable,                 //Ws2_32.dll向上调用转发的函数表
LPWSPPROC_TABLE lpProTable                 //下层提供者的函数表(一般为基础协议,共30个服务函数)
)
{   //如果协议位分层协议或基础协议,那么返回错误
if (lpProtocolInfo->ProtocolChain.ChainLen ProtocolChain.ChainEntries[1];
//遍历所有协议
int i = 0;
for (; i < nTotalProtols; i++)
{//找到下层提供者协议
if (pProtoInfo[i].dwCatalogEntryId == dwBaseEntryId)
{
memcpy(&NextProtocolInfo, &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));
break;
}
}
//如果没找到
if (i >= nTotalProtols)
return WSAEPROVIDERFAILEDINIT;
//加载下层协议的Dll
int nError = 0;
TCHAR szBaseProviderDll[MAX_PATH];
int nLen = MAX_PATH;
//取得下层提供者的DLL路径(可能包含坏境变量)
if(WSCGetProviderPath(&NextProtocolInfo.ProviderId, szBaseProviderDll, &nLen, &nError) == SOCKET_ERROR)
return WSAEPROVIDERFAILEDINIT;
//坏境变量转换字符串
if(!ExpandEnvironmentStrings(szBaseProviderDll, szBaseProviderDll, MAX_PATH))
return WSAEPROVIDERFAILEDINIT;
//加载dll
HMODULE hModdule = LoadLibrary(szBaseProviderDll);
if(hModdule == NULL)
return WSAEPROVIDERFAILEDINIT;
//取出下层提供者的WSPStartup函数
LPWSPSTARTUP pfnWSPStartup = (LPWSPSTARTUP)GetProcAddress(hModdule, "WSPStartup");
if(NULL == pfnWSPStartup )
return WSAEPROVIDERFAILEDINIT;
LPWSAPROTOCOL_INFOW pInfo = lpProtocolInfo;
if (NextProtocolInfo.ProtocolChain.ChainLen == BASE_PROTOCOL)//如果下层提供者是基础协议
pInfo = &NextProtocolInfo;                               //赋给pInfo指针
//调用下层提供者的初始化函数
int nRet = pfnWSPStartup(wVersionRequested, lpWSPData, lpProtocolInfo, UpcallTable, lpProTable);
//初始化失败
if (nRet != ERROR_SUCCESS)
return nRet;

//初始化完成后,复制下层提供者(基础协议)的整个函数表
g_NextProcTable = *lpProTable;
//将基础协议的SendTo函数指针,指向我们的WSPSendTo函数,在我们的函数内,再确定要不要调用回基础协议的Sendto函数
lpProTable->lpWSPSendTo = WSPSendTo; 
lpProTable->lpWSPConnect = WSPConnect;
FreeProvider(pProtoInfo, nTotalProtols);
return nRet;
}

//下面对sendto、connect函数的8888端口进行拦截:

int WSPAPI WSPConnect(       //自定义的WSPConnect函数
SOCKET s,
const struct sockaddr FAR * name,
int namelen,
LPWSABUF lpCallerData,
LPWSABUF lpCalleeData,
LPQOS lpSQOS,
LPQOS lpGQOS,
LPINT lpErrno
)
{
sockaddr_in* info = (sockaddr_in*)name;
USHORT port = ntohs(info->sin_port);
if (port == 8888)   //如果是8888端口,那么拦截
{
int nError = 0;
               //因为整个dll已经加载进程序里,这里对我的控制台程序进行测试
SetConsoleTitle(_T("sorry,we shutdown you tcp protocol port!")); 
g_NextProcTable.lpWSPShutdown(s, SD_BOTH, &nError);
//设置错误信息
*lpErrno = WSAECONNABORTED;   
return SOCKET_ERROR; 
}
       //如果不是,调用下层提供者的函数表中的WSPConnect函数
return g_NextProcTable.lpWSPConnect(s, name, namelen, lpCallerData, lpCalleeData, lpSQOS, lpGQOS, lpErrno);
}
int WSPAPI WSPSendTo         //自定义的WSPSendTo函数
(
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesSent,
DWORD dwFlags,
const struct sockaddr FAR * lpTo,
int iTolen,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
LPWSATHREADID lpThreadId,
LPINT lpErrno
)
{
sockaddr_in* info = (sockaddr_in*)lpTo;
USHORT port = ntohs(info->sin_port);
if (port == 8888)    //如果是8888端口,那么拦截
{
int nError = 0;
SetConsoleTitle(_T("sorry,we shutdown you udp protocol port!"));
g_NextProcTable.lpWSPShutdown(s, SD_BOTH, &nError);
//设置错误信息
*lpErrno = WSAECONNABORTED;
return SOCKET_ERROR;
}
        //如果不是,调用下层提供者的函数表中的WSPSendTo函数
return g_NextProcTable.lpWSPSendTo(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags,
lpTo, iTolen, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno);
}

【5】LSP的DLL编写完成后,编写安装与卸载LSP的程序:


一、简述:1、安装、卸载LSP必须是管理员用户组的权限才能使用.2、下面的例子中,我一共安装了1个分层协议(DLL),3个协议链(用于抢在TCP、UDP、原始套接字提供者前执行)3、在http://blog.csdn.net/aaron133/article/details/78005779篇中的     “网络程序是如何调用Winsock2 服务提供者进行网络通讯”    调用网络通讯的机制,所以要将新安装的协议链,排在遍历函数的最前面,网络程序先找到适合的协议,就会用那个协议,如果排在后面,就可能载入别的相同类型的协议的提供者,而不使用我们的分层提供者.
二、开始编写安装LSP程序:
【编写步骤分析】一、遍历所有协议,将UDP、TCP、原始的Winsock目录入口(结构体)各复制一份出来.二、随便找一个下层协议(基础服务提供者)的Winsock目录入口结构体作为模板,用于安装LSP时作为它的Winsock目录入口(结构体).1、必须修改协议名称(szProtocol成员).2、dwServiceFlags1成员必须将XP1_IFS_HANDLES标志去掉.
3、提供者的类型:ProtocolChain成员ChainLen变量 = LAYERED_PROTOCOL(0) //0暗示为分层协议提供者    不懂这个概念的先看我上一篇讲解SPI文章.//地址:http://blog.csdn.net/aaron133/article/details/78005779
4、表示方式:dwProviderFlags成员 = PFL_HIDDEN; //由提供者自己设置的Winsock目录入口.5、安装分层协议提供者.
三、安装3个协议链(协议链,排在第一位的就是我们新安装的分层提供者)1、为什么有3个协议链,因为它们各对应一个基础协议提供者,分别是TCP、UDP、原始,当网络程序使用TCP、UDP、原始,会先加载我们的分层服务提供者LSP的DLL。
四、重新排序Winsock目录1、因为新安装的提供者,都会排在最后,这样如果前面有网络程序适合的提供者时,就会直接载入它的DLL,而不载入我们LSP的DLL.头文件:

#include#include#include#include#include#include#include#includeusing namespace std;
#pragma warning(disable:4996)
#pragma comment(lib,"Sporder.lib")
#pragma comment(lib, "Ws2_32.lib")
#include//安装LSP
class installLSP
{
public:
installLSP()
{
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);
CoCreateGuid(&this->Layered_guid);
CoCreateGuid(&this->AgreementChain_guid);
}
~installLSP()
{
WSACleanup();
}
public:
//安装LSP,并安装3个协议链
BOOL InstallProvider(WCHAR* wszDllPath)  //参数:LSP的DLL的地址
{
WCHAR wszLSPName[] = _T("AaronLSP");
LPWSAPROTOCOL_INFOW pProtoInfo = NULL;
int nProtocols = 0; //分层协议     取出来的模板
WSAPROTOCOL_INFOW OriginalProtocolInfo[3]; //数组成员为TCP、UDP、原始的目录入口信息
DWORD dwOrigCatalogId[3]; //记录入口ID号
int nArrayCount = 0;      //数组个数索引
DWORD dwLayeredCatalogId; //分层协议的入口ID号
int nError;
pProtoInfo = GetProvider(&nProtocols);
if (nProtocols < 1 || pProtoInfo == NULL)
return FALSE;
BOOL bFindUdp = FALSE;
BOOL bFindTcp = FALSE;
BOOL bFindRaw = FALSE;
for (int i = 0; i < nProtocols; i++)
{   //查找地址族为AF_INET的协议
if (pProtoInfo[i].iAddressFamily == AF_INET)
{
if (!bFindUdp && pProtoInfo[i].iProtocol == IPPROTO_UDP)
{
memcpy(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));
//去除XP1_IFS_HANDLES标志,防止提供者返回的句柄是真正的操作系统句柄
OriginalProtocolInfo[nArrayCount].dwServiceFlags1 &= (~XP1_IFS_HANDLES);
//记录目录入口ID
dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId; 
bFindUdp = TRUE;
}
if (!bFindTcp && pProtoInfo[i].iProtocol == IPPROTO_TCP)
{
memcpy(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));
//去除XP1_IFS_HANDLES标志,防止提供者返回的句柄是真正的操作系统句柄
OriginalProtocolInfo[nArrayCount].dwServiceFlags1 &= (~XP1_IFS_HANDLES);
//记录目录入口ID
dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;
bFindTcp = TRUE;
}
if (!bFindRaw && pProtoInfo[i].iProtocol == IPPROTO_IP)
{
memcpy(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));
//去除XP1_IFS_HANDLES标志,防止提供者返回的句柄是真正的操作系统句柄
OriginalProtocolInfo[nArrayCount].dwServiceFlags1 &= (~XP1_IFS_HANDLES);
//记录目录入口ID
dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;
bFindRaw = TRUE;
}
}
}
if (nArrayCount == 0)
{
FreeProvider(pProtoInfo);
return FALSE;
}
//安装LSP分层协议
WSAPROTOCOL_INFOW LayeredProtocolInfo;


memcpy(&LayeredProtocolInfo, &OriginalProtocolInfo[0], sizeof(WSAPROTOCOL_INFOW));
//修改协议名称的字符串
wcscpy(LayeredProtocolInfo.szProtocol, wszLSPName);
//表示分层协议
LayeredProtocolInfo.ProtocolChain.ChainLen = LAYERED_PROTOCOL;//0
//表示方式为由提供者自己设置
LayeredProtocolInfo.dwProviderFlags = PFL_HIDDEN;
//安装分层协议
if (SOCKET_ERROR == WSCInstallProvider(&Layered_guid, wszDllPath, &LayeredProtocolInfo, 1, &nError))
{
FreeProvider(pProtoInfo);
return FALSE;
}
FreeProvider(pProtoInfo);
//重新遍历协议,获取分层协议的目录ID号
pProtoInfo = GetProvider(&nProtocols);
if (nProtocols < 1 || pProtoInfo == NULL)
return FALSE;
for (int i = 0; i < nProtocols; i++)//一般安装新入口后,会排在最低部
{
if (memcmp(&pProtoInfo[i].ProviderId, &Layered_guid, sizeof(GUID)) == 0)
{
//取出分层协议的目录入口ID
dwLayeredCatalogId = pProtoInfo[i].dwCatalogEntryId;
break;
}
}
//安装协议链                 256
WCHAR wszChainName[WSAPROTOCOL_LEN + 1];//新分层协议的名称  over   取出来的入口模板的名称
for (int i = 0; i < nArrayCount; i++)
{
swprintf(wszChainName, _T("%s over %s"), wszLSPName, OriginalProtocolInfo[i].szProtocol);
wcscpy(OriginalProtocolInfo[i].szProtocol, wszChainName);  //将这个模板的名称改成新名称↑
if (OriginalProtocolInfo[i].ProtocolChain.ChainLen == 1)//这是基础协议的模板
{   //修改基础协议模板的协议链, 在协议链[1]写入真正UDP[基础协议]的入口ID
OriginalProtocolInfo[i].ProtocolChain.ChainEntries[1] = dwOrigCatalogId[i];
}
else
{//如果大于1,相当于是个协议链,表示:将协议链中的入口ID,全部向后退一格,留出[0]
for (int j = OriginalProtocolInfo[i].ProtocolChain.ChainLen; j > 0; j--)
OriginalProtocolInfo[i].ProtocolChain.ChainEntries[j] = OriginalProtocolInfo[i].ProtocolChain.ChainEntries[j - 1];
}
//让新分层协议排在基础协议的前面(如果为协议链排就排在开头了)
OriginalProtocolInfo[i].ProtocolChain.ChainLen++;
OriginalProtocolInfo[i].ProtocolChain.ChainEntries[0] = dwLayeredCatalogId;
}
//一次安装3个协议链
if (SOCKET_ERROR == WSCInstallProvider(&AgreementChain_guid, wszDllPath, OriginalProtocolInfo, nArrayCount, &nError))
{
FreeProvider(pProtoInfo);
return FALSE;
}
//第三步:将所有3种协议进行重新排序,以让系统先调用我们的协议(让协议链排第一,协议链中[0]是新分层协议,[1]基础UDP协议)
//重新遍历所有协议
FreeProvider(pProtoInfo);
pProtoInfo = GetProvider(&nProtocols);
if (nProtocols < 1 || pProtoInfo == NULL)
return FALSE;
DWORD dwIds[20];
int nIndex = 0;
//添加我们的协议链
for (int i = 0; i < nProtocols; i++)
{//如果是我们新创建的协议链
if (pProtoInfo[i].ProtocolChain.ChainLen > 1 && pProtoInfo[i].ProtocolChain.ChainEntries[0] == dwLayeredCatalogId)
dwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId;//将3个协议链排在前3
}
//添加其他协议
for (int i = 0; i < nProtocols; i++)
{//如果是基础协议,分层协议(不包括我们的协议链,但包括我们的分层协议)
if (pProtoInfo[i].ProtocolChain.ChainLen <= 1 || pProtoInfo[i].ProtocolChain.ChainEntries[0] != dwLayeredCatalogId)
dwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId;
}
//重新排序Winsock目录
if (WSCWriteProviderOrder(dwIds, nIndex) != ERROR_SUCCESS)
return FALSE;
FreeProvider(pProtoInfo);
return TRUE;
}
        //卸载LSP
void RemoveProvider()
{
LPWSAPROTOCOL_INFOW pProtoInfo = NULL;
int nProtocols = 0;
DWORD dwLayeredCatalogId = 0; //分层协议提供者的入口ID号
 //遍历出所有协议
pProtoInfo = GetProvider(&nProtocols);
if (nProtocols < 1 || pProtoInfo == NULL)
return;
int nError = 0;
int i = 0;
for (i = 0; i < nProtocols; i++)
{ //查找分层协议提供者
if (memcmp(&Layered_guid, &pProtoInfo[i].ProviderId, sizeof(GUID)) == 0)
{
dwLayeredCatalogId = pProtoInfo[i].dwCatalogEntryId;
break;
}
}
if (i < nProtocols)
{
for (i = 0; i < nProtocols; i++)
{//查找协议链(这个协议链的[0]为分层协议提供者)
if (pProtoInfo[i].ProtocolChain.ChainLen > 1 && pProtoInfo[i].ProtocolChain.ChainEntries[0] == dwLayeredCatalogId)
{//先卸载协议链
WSCDeinstallProvider(&pProtoInfo[i].ProviderId, &nError);
break;
}
}
WSCDeinstallProvider(&Layered_guid, &nError);
}
}
private:
       //这两个函数是遍历所有协议函数,在编写DLL时,已经把源代码放出来了,这里就不放出来了.
       LPWSAPROTOCOL_INFOW GetProvider(LPINT lpnTotalProtocols);
       void FreeProvider(LPWSAPROTOCOL_INFOW pProtoInfo); 
private:
GUID Layered_guid;        //分层协议GUID
GUID AgreementChain_guid; //协议链GUID
};

源文件:

#include "Hello.h"
#define PATH _T("C:\Users\Administrator\Desktop\实例\网络实验\安装LSP服务提供程序\LSPDll\Debug\LSPDll.dll")
int main(int argc,char** argv)
{
system("color 4e");
SetConsoleTitle(_T("安装LSP提供者程序实验"));
ProtocolTraversestheExperiment2 s;
printf("安装LSP前的所有协议:rn");
s.ShowAllProtocol();
installLSP LSP;
LSP.InstallProvider(PATH);
printf("安装LSP后的所有协议:rn");
s.ShowAllProtocol();
getchar();
LSP.RemoveProvider();
printf("清除LSP完成rn");
getchar();
return 0;
}


【测试】1、安装了一个LSP分层服务提供者(相当于HOOK了TCP、UDP、原始套接字),三个协议链


2、当有程序使用8888端口进行TCP连接或8888端口使用UDP发送数据时,就会拦截禁止:
附加说明:1、Sporder.dll在编写LSP程序时,32位放在WOWSys64文件夹、64位放在system32文件夹.2、发布时必须携带着Sporder.dll在程序目录存放.3、编写64位LSP程序的程序时,不要包含#pragma comment(lib,"Sporder.lib")否则程序出错!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

其实在 c++语言里面const修饰的才算是一个真正的常量,在 c 语言中 const 可以说是个“冒牌货”。为什么会这样?其实是 c++ 编译器对 const 进行了加强,当 c++ 编译器遇到常量声明时,不会像 c...

关键字: c++ C语言 const

返回函数的引用去初始化一个新的引用这个和前面一样,都是不会产生副本,但是现在是用返回值去初始化一个引用声明c,也就是说这时候变成了变量temp的别名,在c的生命周期内temp是一直有效的,这样做完全可以。

关键字: c++ 返回值 引用声明

C++是一种面向对象的高级程序设计语言,是C语言的超集。

关键字: c++ C语言

大家好,我是小林。不知道大家当初是怎么学网络编程的?我来说说我踩过的坑。我当初在学网络编程的时候,看见网上的人都说《Unix网络编程》是网络编程圣经,豆瓣评分也很高,那么好学的小林,那肯定毫无犹豫买了。书到货后,我瞬间就...

关键字: 网络编程

什么是网络编程?用一句话概括,就是对网络协议的落地。 落地,意味着对实战的要求更高。所以,一些朋友更喜欢用类似Netty这种封装好的框架——快速,高效。确实,跟开发细节相比,我们常常更看重开发效率。 可日常的项目里,我们...

关键字: 网络编程

什么是网络编程?用一句话概括,就是对网络协议的落地。 落地,意味着对实战的要求更高。所以,一些朋友更喜欢用类似Netty这种封装好的框架——快速,高效。确实,跟开发细节相比,我们常常更看重开发效率。 可日常的项目里,我们...

关键字: 网络编程

什么是网络编程?用一句话概括,就是对网络协议的落地。 落地,意味着对实战的要求更高。所以,一些朋友更喜欢用类似Netty这种封装好的框架——快速,高效。确实,跟开发细节相比,我们常常更看重开发效率。 可日常的项目里,我们...

关键字: 网络编程

在嵌入式行业网络编程使用相对较少,主流应用集中在NB-IOT、Lora、Mqtt这一块,原理上一般是通过加入硬件模块或者是使用第三方SDK来实现。

关键字: 网络编程 嵌入式 tcp

五种IO模型包括:阻塞IO、非阻塞IO、IO多路复用、信号驱动IO、异步IO。

关键字: 嵌入式 网络编程

进行程序开发的同学,无论Web前端开发、Web后端开发,还是搜索引擎和大数据,几乎所有的开发领域都会涉及到网络编程。比如我们进行Web服务端开发,除了Web协议本身依赖网络外,通常还需要连接数据

关键字: 网络编程 数据包 TCP协议 CLIENT
关闭
关闭