📄 nonblkng.c
字号:
/*---------------------------------------------------------------------------
* Program: WAL.EXE WinSock Application Launcher
*
* filename: nonblkng.c,
*
* copyright by Bob Quinn, 1995
*
* Description:
* This module contains the Windows Sockets network code in a
* sample application that does non-blocking calls.
*
* 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 <windowsx.h>
#include <winsock.h> /* Windows Sockets */
#include <string.h> /* for _fxxxxx() functions */
#include "resource.h"
#include "..\winsockx.h"
#include "wal.h"
/*---------------------------------------------------------------------------
* Function: nb_ds_cn()
*
* Description:
* Blocking datastream connect.
*
*/
int nb_ds_cn (HANDLE hInst, HANDLE hwnd)
{
struct sockaddr_in stLclAddr; /* Socket structure */
int wRet = SOCKET_ERROR, i; /* work variables */
fd_set stWritFDS; /* select() "file descriptor set" structures */
fd_set stXcptFDS;
struct timeval stTimeOut; /* for select() timeout (none) */
BOOL bInProgress = FALSE;
u_long lOnOff;
int nWSAerror;
/* Get a TCP socket (if we don't have one already) */
if (stWSAppData.nSockState == STATE_NONE) {
stWSAppData.nSock = socket (AF_INET, SOCK_STREAM, 0);
if (stWSAppData.nSock == INVALID_SOCKET) {
WSAperror(WSAGetLastError(), "socket()", hInst);
goto AppExit;
}
/*---------------------------------*/
stWSAppData.nSockState = STATE_OPEN;
/*---------------------------------*/
}
/* Enable OOBInLine option if user asked to enable it */
if (stWSAppData.nOptions & OPTION_OOBINLINE) {
set_oobinline (hInst, hwnd, TRUE);
}
/* Initialize the Sockets Internet Address (sockaddr_in) structure */
_fmemset ((LPSTR)&(stLclAddr), 0, sizeof(struct sockaddr_in));
/* Get IP Address from a hostname (or addr string in dot-notation) */
stLclAddr.sin_addr.s_addr = GetAddr (stWSAppData.szHost);
/* make our socket non-blocking */
lOnOff = TRUE;
wRet = ioctlsocket(stWSAppData.nSock, FIONBIO, (u_long FAR *)&lOnOff);
if (wRet) { /* ioctlsocket() returns 0 on success */
nb_close (hInst, hwnd);
WSAperror(WSAGetLastError(), (LPSTR)"ioctlsocket()", hInst);
goto AppExit;
}
/* convert port number from host byte order to network byte order */
stLclAddr.sin_port = htons (stWSAppData.nPortNumber);
stLclAddr.sin_family = PF_INET; /* Internet Address Family */
/*----------------------------------------*/
stWSAppData.nSockState = STATE_CONN_PENDING;
/*----------------------------------------*/
#if 0
/*------------------- Example of what NOT to do ---------------------------
* This is one algorithm for detecting a TCP connection on a non-blocking
* socket that was used in BSD Sockets. Don't do this!
*
* We don't connect() non-blocking this way because it is too dependent
* on specific error values to detect socket state. It does not work
* because on Microsoft TCP/IP and others the second call to connect()
* call gives WSAEINVAL instead of the expected (BSD-compatible)
* WSAEALREADY.
*
* The more robust and reliable way to detect the connection on a non-
* blocking socket--other than WSAAsyncSelect()--is to use select()
* (which blocks).
*/
i = 0;
do {
i++;
wRet = connect(stWSAppData.nSock,
(struct sockaddr FAR*)&stLclAddr,
sizeof(struct sockaddr_in));
/* on non-blocking connect, we expect errors:
* - WSAEISCONN means success
* - some mean retry
* - some others are bad news
*/
if (wRet == SOCKET_ERROR) {
nWSAerror = WSAGetLastError();
if (nWSAerror == WSAEISCONN) {
/* we're connected!! */
break;
} else if ((nWSAerror == WSAEWOULDBLOCK) ||
(nWSAerror == WSAEINPROGRESS) ||
(nWSAerror == WSAEALREADY)) {
/* need to retry */
bInProgress = TRUE;
} else {
/* fatal error */
wsprintf (achOutBuf, "connect(%d)", i);
nb_close (hInst, hwnd);
WSAperror(nWSAerror, achOutBuf, hInst);
goto AppExit;
}
}
} while (bInProgress);
/*---------------------End of example what NOT to do---------------*/
#endif
/*-------------------- begin using select() --------------------
* The proper (BSD-compatible) way to do a non-blocking connect()
* in a loop does not work on many WinSocks (which return WSAEINVAL
* on 2nd and subsequent connect() calls, instead of WSAEALREADY).
*
* Although using select() to detect connection completion is a
* blocking call, it is the best method on a non-blocking socket.
*
* We'll allow a certain number of timeouts (e.g. select() returns
* the value 0), then fail.
*/
/* Now wait for "writability" to indicate connection completion,
* or an exception to indicate an error */
for (i= 0;;) { /* we deal with counter inside the loop */
wRet = connect(stWSAppData.nSock,
(struct sockaddr FAR*)&stLclAddr,
sizeof(struct sockaddr_in));
/* on non-blocking connect, we expect WSAEWOULDBLOCK error
* but WSAEALREADY is ok too, and WSAEISCONN means we're
* done!
*/
if (wRet == SOCKET_ERROR) {
nWSAerror = WSAGetLastError();
if (nWSAerror == WSAEISCONN) {
/* we're connected!! */
break;
} else if ((nWSAerror != WSAEWOULDBLOCK) &&
(nWSAerror != WSAEALREADY)) {
/* fatal error */
wsprintf (achOutBuf, "connect(%d)", i);
nb_close (hInst, hwnd);
WSAperror(nWSAerror, achOutBuf, hInst);
goto AppExit;
}
}
/* clear all sockets from FDS structure, then put our socket
* into the socket descriptor set */
FD_ZERO((fd_set FAR*)&(stWritFDS));
FD_ZERO((fd_set FAR*)&(stXcptFDS));
#pragma message ("--> WinSock FD_SET macro generates MSVC warning C4127 <--")
FD_SET(stWSAppData.nSock, (fd_set FAR*)&(stWritFDS));
FD_SET(stWSAppData.nSock, (fd_set FAR*)&(stXcptFDS));
/* initialize the timeout structure. We use the same timeout as
* our I/O polling loop. However, we don't want to poll with
* a zero timeout, since we don't have a blocking hook function
* to yield we'll depend on WinSock's default blocking hook.
* We use a nice round number for our timeout: 1 second. */
stTimeOut.tv_sec = CONN_TIMEOUT;
stTimeOut.tv_usec = 0;
wRet = select(-1, /* call select() */
NULL,
(fd_set FAR*)&(stWritFDS),
(fd_set FAR*)&(stXcptFDS),
(struct timeval FAR *)&(stTimeOut));
if (wRet == SOCKET_ERROR) { /* check return */
/* all errors are bad news */
nb_close (hInst, hwnd);
WSAperror(WSAGetLastError(), "select()", hInst);
goto AppExit;
} else if (wRet > 0) {
/* check for error (exception) first */
if (FD_ISSET (stWSAppData.nSock,
(fd_set FAR*)&(stXcptFDS))) {
/* all errors are bad news */
nb_close (hInst, hwnd);
WSAperror(WSAGetLastError(),"select(excptn)", hInst);
goto AppExit;
}
if (FD_ISSET (stWSAppData.nSock,(fd_set FAR*)&(stWritFDS))) {
/* If "writable" socket set includes ours, we're connected! */
break;
} else {
/* This should never happen!!! If select returned
* a positive value, something should be set in
* either our exception or our read socket set */
MessageBox(hwnd,
"Unexpected results from select()",
"Error", MB_OK | MB_ICONHAND);
nb_close(hwnd, hInst);
goto AppExit; /* bail! */
}
} else { /* wRet == 0 which indicates select() timeout */
i++; /* increment our timeout counter */
if (i++ >= CONN_RETRIES) {
/* if we've had our fill of retries, report error and exit */
MessageBox(hwnd,
"select() timeout exceeded",
"Error", MB_OK | MB_ICONHAND);
nb_close(hwnd, hInst);
goto AppExit;
}
}
}
/*-------------------- end using select() --------------------*/
/*-------------------------------------*/
stWSAppData.nSockState = STATE_CONNECTED;
/*-------------------------------------*/
/* get timers for statistics updates & I/O (if requested) */
get_timers(hInst, hwnd);
/* Tell ourselves to do next step! */
PostMessage(hwnd, WM_COMMAND, anIoCmd[stWSAppData.nIoMode], 0L);
AppExit:
return (wRet);
} /* end nb_ds_cn() */
/*---------------------------------------------------------------------------
* Function: nb_ds_ls()
*
* Description:
* Blocking datastream listen/accept
*
*/
int nb_ds_ls (HANDLE hInst, HANDLE hwnd)
{
struct sockaddr_in stLclAddr; /* Socket structures */
struct sockaddr_in stRmtAddr;
int nAddrLen; /* for length of address structure */
u_long lOnOff; /* on/off switch for ioctlsocket() command */
SOCKET hNewSock; /* new socket returned from accept() */
fd_set stReadFDS; /* select() "file descriptor set" structures */
fd_set stXcptFDS;
struct timeval stTimeOut; /* for select() timeout (none) */
int wRet = SOCKET_ERROR; /* work variables */
int nWSAerror;
/* Get a TCP socket (if we don't already have one) */
if (stWSAppData.nSockState == STATE_NONE) {
stWSAppData.nSock = socket (AF_INET, SOCK_STREAM, 0);
if (stWSAppData.nSock == INVALID_SOCKET) {
WSAperror(WSAGetLastError(),"socket()", hInst);
goto AppExit;
}
/*---------------------------------*/
stWSAppData.nSockState = STATE_OPEN;
/*---------------------------------*/
}
/* Enable OOBInLine option if user asked to enable it */
if (stWSAppData.nOptions & OPTION_OOBINLINE) {
set_oobinline (hInst, hwnd, TRUE);
}
/* make our socket non-blocking */
lOnOff = TRUE;
wRet = ioctlsocket(stWSAppData.nSock, FIONBIO, (u_long FAR *)&lOnOff);
if (wRet) { /* ioctlsocket() returns 0 on success */
nb_close (hInst, hwnd);
WSAperror(WSAGetLastError(), "ioctlsocket()", hInst);
goto AppExit;
}
/* convert port number from host byte order to network byte order */
stLclAddr.sin_port = htons (stWSAppData.nPortNumber);
stLclAddr.sin_addr.s_addr = 0L; /* no restriction on address */
stLclAddr.sin_family = PF_INET; /* Internet Address Family */
/* Name the local socket */
wRet = bind(stWSAppData.nSock,
(struct sockaddr FAR*)&stLclAddr,
sizeof(struct sockaddr_in));
if (wRet == SOCKET_ERROR) {
nb_close (hInst, hwnd);
WSAperror(WSAGetLastError(),"bind()", hInst);
goto AppExit;
}
/*---------------------------------*/
stWSAppData.nSockState = STATE_BOUND;
/*---------------------------------*/
/* Begin listening for incoming connections on socket */
wRet = listen(stWSAppData.nSock, 1);
if (wRet == SOCKET_ERROR) {
nb_close (hInst, hwnd);
WSAperror(WSAGetLastError(), "listen()", hInst);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -