During the development process, you often need to simulate various bandwidths to simulate the user's situation as much as possible and solve some corner cases. However, due to poor tools, it is time-and effort-consuming and we cannot get good results. There are not many software related to bandwidth restrictions. Net limiter in foreign countries is not charged. So it took two days to implement a simple time according to your own needs. The principle is to use LSP filtering. The following is a brief introduction.
1. What is LSP?
LSP-layered service provider. The official introduction is very complicated. To put it simply, it is similar to the function of hook socket. For example, if wsasend is called in your program, a wspsend corresponds to the LSP.
2. Where to start?
Microsoft is still very powerful and provides an LSP example. Most programs are transformed based on this example. The example is located in Microsoft sdks/Windows/v6.0/samples/netds/Winsock/LSP and is part of the Windows SDK.
3. Ifs vs nonifs
To be honest, I am not very clear. I use nonifs. Reference section:
"Ifs LSP uses an actual OS I/O handle per socket, which means that handles passed from the LSP
To the upper layer or application do not need translation.
Non-ifs LSP allocates its own handle per socket, which means that handles passed from the LSP
To the upper layer of application must be translated by the LSP when it passes all the commands
To its lower-layer LSP or base provider.
It is important to understand that from an installer point of view, each LSP needs to be installed
Differently. Non-ifs LSP can be layered into any position in the stack. Ifs LSP must be installed
First after the base providers or after another ifs-based LSP. However, ifs LSP cannot be
Installed after a non-ifs LSP. Another important point is that the installer needs to set a special
Flag to denote that the ifs lsp is installed in the stack ."
4. Special reminder:
Before you start, you 'd better back up the following items in the registry. Although normal operations do not cause exceptions, they can be restored in case of exceptions:
HKEY_LOCAL_MACHINE/system/CurrentControlSet/services/Winsock2
5.Install LSP
In the MS example, the installation is the project under the install directory, and a command line program is compiled. You can see the README in the installation help. However, administrator permissions are required under Vista. My program is an MFC program. You only need to click Install to install it. Uninstall will uninstall it. I installed UDP and TCP in overload mode and searched for them by name. I am not sure if every computer is the same. If they are different, I can change them slightly.
6. Limit the bandwidth:
The bandwidth control for UDP sending is still very simple. I added the bandwidth control code in wspsend and wspsendto, And I will understand it at a glance. However, it is a bit difficult to control the received bandwidth. Because the asynchronous mode of the socket has a complete port, you need to change the wspreceive, wspreceivefrom, and intermediatecompletionroutine. I have simply written the code in intermediatecompletionroutine, not tested, because my project does not need to be processed;) but it should not be difficult.
Bool checkrecvbandwidth (DWORD dwrecvedbytes, sock_info * socketcontext) <br/>{< br/> If (m_wlimitudpport! = 0 & m_wlimitudpport = socketcontext-> wport & socketcontext-> protcol = ipproto_udp) <br/>{< br/> If (m_udpreceiveflow.wport = 0) <br/>{< br/> m_udpreceiveflow.wport = m_wlimitudpport; <br/> latency = timegettime (); <br/> dbuplint ("checkrecvbandwidth limit initialized, limited BPS = % d ", m_dwlimitedrecvbps); <br/>}< br/> m_udpreceiveflow.dwtotalbytes + = dwrecvedbytes; </P> <p> double BPS = 0; <br/> DWORD dwdiff = timegettime ()-interval; <br/> If (dwdiff> 0) <br/> BPS = m_udpreceiveflow.dwtotalbytes * 8000.0/dwdiff; <br/> // dbuplint ("checkrecvbandwidth: Send flow Port = % d, total = % d dwdiff = % d, first = % d, BPS = % d", m_udpreceiveflow.wport, m_udpreceiveflow.dwtotalbytes, timegettime (), interval, long (BPS); <br/> If (BPS> m_dwlimitedrecvbps) <br/>{< br/> dbuplint ("checkrecvbandwidth: bandwidth exceed the limited, current BPS = % d ", INT (BPS); <br/> m_udpreceiveflow.dwtotalbytes-= dwrecvedbytes; <br/> return true; <br/>}< br/> return false; <br/>}< br/>
Add the following code after calling the receive of the underlying provider:
Setblockingprovider (socketcontext-> provider); <br/> ret = socketcontext-> provider-> nextproctable. lpwsprecv (<br/> socketcontext-> providersocket, <br/> lpbuffers, <br/> dwbuffercount, <br/> lpnumberofbytesrecvd, <br/> lpflags, <br/> lpoverlapped, <br/> lpcompletionroutine, <br/> lpthreadid, <br/> lperrno); <br/> setblockingprovider (null ); <br/> If (socket_error! = RET) <br/>{< br/> If (* lpnumberofbytesrecvd> 0 & checkrecvbandwidth (* lpnumberofbytesrecvd, socketcontext )) <br/>{< br/> * lpnumberofbytesrecvd = 0; <br/> * lperrno = 10035; <br/>}< br/> socketcontext-> bytesrecv + = * lpnumberofbytesrecvd; <br/>}< br/>
7. Process Communication
Because the LSP is deployed in the target process, I need multi-process communication to control the bandwidth. I use the shared memory method.
# Pragma data_seg ("shared") <br/> udp_flow m_udpsendflow = {0}; <br/> udp_flow m_udpreceiveflow = {0}; <br/> word m_wlimitudpport = 0; <br/> DWORD m_dwlimitedsendbps = 33 <10; <br/> DWORD m_dwlimitedrecvbps = 56 <10; <br/> # pragma data_seg () </P> <p> # pragma comment (linker, "/section: shared, RWS") <br/>
8. About debugging:
Because this cannot be directly debugged, you can only view it by dbgview. In addition, it is time-consuming to restart the system after uninstalling and replacing it.
9 .:
Finally, I shared my modified program with the compilation result (the Microsoft example has no project, and it is difficult to set up) and used the vs2008 project.
Http://cppxml.googlecode.com/files/MyNetLimiter_src.rar
For my work, refer to this article: Workshop.