📄 wal.c
字号:
/*---------------------------------------------------------------------
*
* Program: WAL.EXE WinSock Application Launcher
*
* filename: wal.c
*
* copyright by Bob Quinn, 1995
*
* Description:
* WinSock test and performance analysis application that allows
* launching of tcp or udp, clients or servers, using blocking,
* non-blocking or asynchronous operation modes. Socket options
* and many application I/O parameters are available to alter
* the application operation before or during execution.
*
* This software is not subject to any export provision of
* the United States Department of Commerce, and may be
* exported to any country or planet.
*
* Permission is granted to anyone to use this software for any
* purpose on any computer system, and to alter it and redistribute
* it freely, subject to the following restrictions:
*
* 1. The author is not responsible for the consequences of
* use of this software, no matter how awful, even if they
* arise from flaws in it.
*
* 2. The origin of this software must not be misrepresented,
* either by explicit claim or by omission. Since few users
* ever read sources, credits must appear in the documentation.
*
* 3. Altered versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
* Since few users ever read sources, credits must appear in
* the documentation.
*
* 4. This notice may not be removed or altered.
*
---------------------------------------------------------------------*/
#include <windows.h>
#include <winsock.h> /* Windows Sockets */
#include <windowsx.h> /* for WinNT */
#include <string.h> /* for _fmemcpy() & _fmemset() */
#include "..\winsockx.h"
#include "wal.h"
/*------------ global variables ------------*/
char szWALClass [] = "WinSock Application Launcher";
int wChargenLen; /* length of string to be output */
char achChargenBuf[2*BUF_SIZE]; /* we put CHARGEN_SEQ string resource here */
int cbBufSize;
char achInBuf [BUF_SIZE]; /* Input Buffer */
char achOutBuf [BUF_SIZE]; /* Output Buffer */
int recv_count; /* number of calls to recv() on FD_READ */
/* socket name structures (for IP addresses & ports) */
struct sockaddr_in stLclSockName, stRmtSockName;
BOOL bShowDetail = FALSE; /* toggle for detail statistics */
u_long lCallCount=0; /* Total number I/O function calls */
WSAPP stWSAppData; /* Application data */
/* Table of application ID's from which we launch based on user choice */
int anWSAppTable[2][2][3] = { /* Role, Protocol, Mode */
BL_DS_CL, NB_DS_CL, AS_DS_CL,
BL_DG_CL, NB_DG_CL, AS_DG_CL,
BL_DS_SV, NB_DS_SV, AS_DS_SV,
BL_DG_SV, NB_DG_SV, AS_DG_SV,
};
/* strings describing the current socket state */
static LPSTR szSockState[] = {
"none (no socket)",
"open",
"named (bound)",
"listening",
"accept pending",
"connect pending",
"connected",
"close pending"
};
/* this table translates our I/O mode index into the WM_COMMAND I/O mode message */
int anIoCmd[] = {
IDM_WRITE_READ,
IDM_READ_WRITE,
IDM_READ,
IDM_WRITE
};
/* this table contains default settings and it's indexed by operation mode
* (e.g. OPMODE_BL, OPMODE_NB, or OPMODE_AS) */
OPMODEOPTION astOpModeOption[] = {
/* fields: nIoMode, nLength, nLoopLimit, nWinTimer, nBytesMax */
{"Blocking", IOMODE_WR,DIX_MSS, DFLT_LOOP_MAX,200,0}, /* blocking mode */
{"NonBlocking", IOMODE_RW,DIX_MSS, DFLT_LOOP_MAX,50, 0}, /* non-blocking mode */
{"Asynchronous",IOMODE_R, DIX_MSS, DFLT_LOOP_MAX,0, 0} /* asynchronous mode */
};
/* BQ NOTE: I need to find out how to make GetProfileString look in the
* same directory where the executable resides */
char szIniFile[] = "WAL.INI";
char szAppOption[] = "AppOptions";
/* this table contains default settings, and it's indexed by I/O mode
* (e.g. read/write, write/read, read or write) and App role (client or server) */
IOMODEOPTION astIoModeOption[][2] = {
/* Client Role: Server Role: */
{{ECHO_PORT, "echo"}, {CHARGEN_PORT, "chargen"}}, /* Write/Read mode */
{{CHARGEN_PORT, "chargen"}, {ECHO_PORT, "echo"}}, /* Read/Write mode */
{{CHARGEN_PORT, "chargen"}, {DISCARD_PORT, "discard"}}, /* Read-only mode */
{{DISCARD_PORT, "discard"}, {CHARGEN_PORT, "chargen"}} /* Write-only mode */
};
WSAPP stWSAppData; /* Our Application's Datastructure */
HWND FAR PASCAL WALInit(HANDLE, HANDLE, int);
/*--------------------------------------------------------------------
* Function: WinMain()
*
* Description:
* initialize and start message loop
*
*/
int PASCAL WinMain
(HANDLE hInstance,
HANDLE hPrevInstance,
LPSTR lpszCmdLine,
int nCmdShow)
{
MSG msg;
int nRet;
HWND hwnd;
hInst = hInstance;
lpszCmdLine = lpszCmdLine; /* avoid warning */
hwnd = WALInit(hInstance, hPrevInstance, nCmdShow); /* initialize! */
if (!hwnd)
return 0;
/*-------------Initialize Windows Sockets DLL------------*/
nRet = WSAStartup(WS_VERSION_REQD, &stWSAData);
/* WSAStartup() returns error value if failed (0 on success) */
if (nRet != 0) {
WSAperror(nRet, "WSAStartup()", hInst);
}
while (GetMessage (&msg, NULL, 0, 0)) { /* main loop */
TranslateMessage(&msg);
DispatchMessage (&msg);
}
/*-------------say good-by to WinSock DLL----------------*/
if (!nRet) { /* only call if WSAStartup() succeeded */
nRet = WSACleanup();
if (nRet == SOCKET_ERROR) {
WSAperror(WSAGetLastError(), "WSACleanup()", hInst);
}
}
return msg.wParam;
} /* end WinMain() */
/*----------------------------------------------------------------------
* Function: WALInit()
*
* Description: Register Window class, create and show main window.
*/
HWND FAR PASCAL WALInit(HANDLE hInst, HANDLE hPrevInst, int nCmdShow)
{
WNDCLASS wc;
HWND hwnd;
if (!hPrevInst) {
/* register WAL's window class */
wc.style = CS_HREDRAW | CS_VREDRAW;
#pragma warning (disable:4050)
wc.lpfnWndProc = WALWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIcon(hInst, IDWALICON);
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground = COLOR_APPWORKSPACE+1;
wc.lpszMenuName = IDWALMENU;
wc.lpszClassName = szWALClass;
if (!RegisterClass (&wc)) {
return (0);
}
}
hwnd = CreateWindow(
szWALClass,
szWALClass,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
500,
300,
NULL,
NULL,
hInst,
NULL
);
if (!hwnd)
return (0);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
return (hwnd);
;
} /* end WALInit() */
/*----------------------------------------------------------------------
* Function: do_stats()
*
* Description: Update on-screen statistics (we do this each time we
* get a timer message, or when user chooses UpdateStats command.
*/
void do_stats (HANDLE hwnd, HANDLE hInst, BOOL bUpdateDetail)
{
PAINTSTRUCT ps;
HDC hdc;
u_long lSeconds, lOutRate=0L, lInRate=0L;
int i, wRet, nSockState, XPos, YPos;
u_long lCallRate;
/*
* Display some stats.
*/
InvalidateRect(hwnd, NULL, TRUE);
hdc = BeginPaint(hwnd, &ps);
/* Calculate time elapsed (in seconds) iff we're connected */
if (stWSAppData.nSockState == STATE_CONNECTED) {
lSeconds = (GetTickCount() - stWSAppData.lStartTime);
if (lSeconds) /* avoid divide by zero */
lSeconds /= 1000L;
if (!lSeconds) /* avoid divide by zero */
lSeconds = 1L;
stWSAppData.lSeconds = lSeconds; /* time elapsed */
} else {
lSeconds = stWSAppData.lSeconds; /* final time */
}
XPos = X_START_POS; /* start position for statistics output */
YPos = Y_START_POS;
wsprintf(achOutBuf, "Bytes Out: %lu In: %lu",
stWSAppData.lBytesOut, stWSAppData.lBytesIn);
TextOut(hdc, XPos, YPos, achOutBuf, _fstrlen((LPSTR)achOutBuf));
YPos += STATTEXT_HGHT;
if (stWSAppData.lBytesOut) /* avoid divide by zero */
lOutRate = stWSAppData.lBytesOut/lSeconds;
if (stWSAppData.lBytesIn)
lInRate = stWSAppData.lBytesIn/lSeconds;
wsprintf(achOutBuf, "Bytes/Sec Out: %lu In: %lu",lOutRate, lInRate);
TextOut(hdc, XPos, YPos, achOutBuf, _fstrlen((LPSTR)achOutBuf));
YPos += STATTEXT_HGHT;
wsprintf(achOutBuf, "Time Up: %lu seconds", (lSeconds==1 ? 0 : lSeconds));
TextOut(hdc, XPos, YPos, achOutBuf, _fstrlen((LPSTR)achOutBuf));
YPos += STATTEXT_HGHT;
wsprintf(achOutBuf, "Timer: %d, Loops: %d (max: %d), Bytes per IO: %d",
stWSAppData.nWinTimer, stWSAppData.nLoopLimit,
stWSAppData.nLoopMax, stWSAppData.nLength);
TextOut(hdc, XPos, YPos, achOutBuf, _fstrlen((LPSTR)achOutBuf));
YPos += STATTEXT_HGHT;
nSockState = stWSAppData.nSockState;
for (i=0; nSockState; i++) { /* convert bit flag to index */
nSockState = nSockState >> 1;
}
wsprintf(achOutBuf, "Socket: %d, Socket State: %s",
stWSAppData.nSock, szSockState[i]);
TextOut(hdc, XPos, YPos, achOutBuf, _fstrlen((LPSTR)achOutBuf));
YPos += STATTEXT_HGHT*2; /* skip a line */
/* If OOB enabled, show OOB data statistics */
if (stWSAppData.nOptions & OPTION_OOBSEND) {
wsprintf(achOutBuf, "OOB data bytes Out: %lu In: %lu",
stWSAppData.lOobBytesOut, stWSAppData.lOobBytesIn);
TextOut(hdc, XPos, YPos, achOutBuf, _fstrlen((LPSTR)achOutBuf));
YPos += STATTEXT_HGHT*2; /* skip a line */
}
/* Update Details (if requested and we have a socket) */
if (bUpdateDetail && (stWSAppData.nSockState > STATE_NONE)) {
int nLen = sizeof (struct sockaddr_in);
_fmemset ((void FAR*)&stLclSockName, 0, nLen);
_fmemset ((void FAR*)&stRmtSockName, 0, nLen);
/* Get Local Socket Name (if we have a socket) */
wRet = getsockname (stWSAppData.nSock,
(struct sockaddr FAR *)&stLclSockName,
(int FAR*)&nLen);
if (wRet == SOCKET_ERROR) {
WSAperror((int)WSAGetLastError(), "getsockname()", hInst);
} else if (stWSAppData.nSockState == STATE_CONNECTED) {
/* Get Remote Socket Name (if we have an association) */
wRet = getpeername (stWSAppData.nSock,
(struct sockaddr FAR *)&stRmtSockName,
(int FAR *)&nLen);
if (wRet == SOCKET_ERROR) {
WSAperror(WSAGetLastError(),"getpeername()", hInst);
}
}
} /* end if (bUpdateDetail) */
/* If details were requested, show them (even if none available yet) */
if (bShowDetail) {
char FAR *szIpAddr;
switch (stWSAppData.nSockState) {
case STATE_NONE:
TextOut (hdc, XPos, YPos,
"No Socket Available", 19);
break;
case STATE_CONN_PENDING:
case STATE_BOUND:
case STATE_LISTENING:
case STATE_ACCEPT_PENDING:
TextOut (hdc, XPos, YPos,
"No Socket Association", 21);
break;
case STATE_CONNECTED:
default:
TextOut (hdc, XPos, YPos,
"getsockname() & getpeername() results:", 38);
}
YPos += STATTEXT_HGHT;
szIpAddr = inet_ntoa (stLclSockName.sin_addr);
wsprintf(achOutBuf, "Local Port: %d, IP Address: %s",
htons (stLclSockName.sin_port),
szIpAddr ? szIpAddr : "unknown");
TextOut(hdc, XPos, YPos, achOutBuf, _fstrlen((LPSTR)achOutBuf));
YPos += STATTEXT_HGHT;
szIpAddr = inet_ntoa (stRmtSockName.sin_addr);
wsprintf(achOutBuf, "Remote Port: %d, IP Address: %s",
htons (stRmtSockName.sin_port),
szIpAddr ? szIpAddr : "unknown");
TextOut(hdc, XPos, YPos, achOutBuf, _fstrlen((LPSTR)achOutBuf));
YPos += STATTEXT_HGHT*2;
lCallRate = stWSAppData.lCallCount / lSeconds;
wsprintf (achOutBuf, "I/O calls per second: %lu", lCallRate);
TextOut(hdc, XPos, YPos, achOutBuf, _fstrlen((LPSTR)achOutBuf));
YPos += STATTEXT_HGHT;
wsprintf (achOutBuf, "back-to-back I/O calls %d (max: %d)",
stWSAppData.nLoopsDn, stWSAppData.nLoopsDnMax);
TextOut(hdc, XPos, YPos, achOutBuf, _fstrlen((LPSTR)achOutBuf));
YPos += STATTEXT_HGHT;
wsprintf (achOutBuf, "well spaced I/O calls %d (max: %d)",
stWSAppData.nLoopsUp, stWSAppData.nLoopsUpMax);
TextOut(hdc, XPos, YPos, achOutBuf, _fstrlen((LPSTR)achOutBuf));
#ifndef WIN32
/* For debugging ...though hasn't revealed any problems yet
* (never seen more than 2 messages in task queue or 1 in
* the system message queue. These functions are in DEBUG.C */
ShowWinTaskQ(hwnd); /* output task queue info to debug */
ShowSystemQ(hdc, XPos, YPos+STATTEXT_HGHT);
#endif
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -