1.2 Bekeley套接口 Windows
Sockets规范是建立在Bekeley套接口模型上的。这个模型现在已是TCP/IP网络的标准。它提供了习惯于UNIX套接口编程的程序员极为熟悉的环境,并且简化了移植现有的基于套接口的应用程序源代码的工作。Windows
Sockets API也是和4.3BSD的要求一致的。
1.3 Microsoft
Windows和针对Windows的扩展 这一套Windows Sockets
API能够在所有3.0以上版本的Windows和所有Windows Scokets实现上使用,所以它不仅为Windwos
Sockets实现和Windows Sockets应用程序提供了16位操作环境,而且也提供了32位操作环境。
Windows
Sockets也支持多线程的Windows进程。一个进程包含了一个或多个同时执行的线程。在Windows
3.1非多线程版本中,一个任务对应了一个仅具有单个线程的进程。而我们在本书中所提到的线程均是指在多线程Windows环境中的真正意义的线程。在非多线程环境中(例如Windows
3.0)这个术语是指Windows Sockets进程. Windows
Sockets规范中的针对Windows的扩展部分为应用程序开发者提供了开发具有Windows应用软件的功能。它有利于使程序员写出更加稳定并且更加高效的程序,也有助于在非占先Windows版本中使多个应用程序在多任务情况下更好地运作。除了WSAStartup()和WSACleanup()两个函数除外,其他的Windows扩展函数的使用不是强制性的。
1.4 这份规范的地位 Windows
Sockets是一份独立的规范。它的产生和存在是为了造益于应用程序开发者,网络软件供应商和广大计算机用户。这份规范的每一份正式出版的版本(非草稿)实际上代表了为网络软件供应商实现所需和应用程序开发者所用的一整套API。关于这套规范的讨论和改进还正在进行之中。这样的讨论主要是通过Internet上的一个电子邮件论坛-winsock@microdyne.com进行的。同时也有不定期的会议举行。会议的具体内容会在电子邮件论坛上发表。
1.5 曾经作过的修改
1.5.1 Windows Sockets 1.0
Windows Sockets
1.0代表了网络软件供应商和用户协会细致周到的工作的结晶。Windows Sockets
1.0规范的发布是为了让网络软件供应商和应用程序开发者能够开始建立各自的符合Windows Sockets标准的实现和应用程序。
2.6.1 套接口数据类型和错误数值 Windows
Sockets规范中定义了一个新的数据类型SOCKET,这一类型的定义对于将来Windows
Sockets规范的升级是必要的。例如在Windows
NT中把套接口作为文件句柄来使用。这一类型的定义也保证了应用程序向Win/32环境的可移植性。因为这一类型会自动地从16位升级到32位。
在UNIX中所有句柄包括套接口句柄,都是非负的短整数,而且一些应用程序把这一假设视为真理。Windows
Sockets句柄则没有这一限制,除了INVALID_SOCKET不是一个有效的套接口外,套接口可以取从0到INVALID_SOCKET-1之间的任意值。
因为SOCKET类型是unsigned,所以编译已经存在于UNIX环境中的应用程序的源代码可能会导致signed/unsigned数据类型不匹配的警告。
这还意味着,在socket()例程和accept()例程返回时,检查是否有错误发生就不应该再使用把返回值和-1比较的方法,或判断返回值是否为负(这两种方法在BSD中都是很普通,很合法的途径)。取而代之的是,一个应用程序应该使用常量INVALID_SOCKET,该常量已在WINSOCK.H中定义。
例如:
典型的BSD风格: s = socket(...);
if (s == -1) /* of s<0
*/
{...}
更优良的风格:
s = socket(...);
if (s == INVALID_SOCKET)
{...}
第三章 Windows
Sockets 1.1应用实例 在本章中,作者的实际工作为背景,给出了一个使用Windows Sockets
1.1编程的具体例子。并对这个例子作了详细的分析。这个例子在Windows 3.1、Windows Sockets 1.1和BSD OS
for PC 2.0(BSD UNIX微机版)环境下调试通过。
/* exit from the while loop */
break;
} /* end if (total_time) */
write_count++; /* incr.
counter of times written */ bytes_sent +=
tmp; /* # of bytes placed on connection */
wsprintf((LPSTR)prbuf,"%ld\n",bytes_sent);
SetDlgItemText(hOurDlg, IDD_SENT, (LPSTR) prbuf);
} /* end if (tmp == -1) */
write_count++; /* incr. counter of times written
*/ bytes_sent += tmp; /* # of bytes placed on
connection */
wsprintf((LPSTR)prbuf,"%ld\n",write_count);
SetDlgItemText(hOurDlg, IDD_WRITE, (LPSTR) prbuf);
wsprintf((LPSTR)prbuf,"%ld\n",bytes_sent);
SetDlgItemText(hOurDlg, IDD_SENT, (LPSTR) prbuf); } /* end while
*/
/* Look for a reply ... NOTE: most hosts won't give *
a 'reply', done to illustrate communication between * sockets.
Our ulisten example will give a reply though. */
SetDlgItemText(hOurDlg, IDD_COMMENT, "Waiting for reply from
server..\n"); while (1) { tmp =
sizeof(dest); i_temp = recvfrom(hSock,(char
FAR *) &ReplyBuffer,sizeof(ReplyBuffer),
0, (struct sockaddr *) &dest, (int FAR *) &tmp);
if (i_temp == SOCKET_ERROR) {
if (h_errno == WSAEWOULDBLOCK) /* if no data,
read again */ continue;
else {
/* any error besides these. just punt */
wshout_err (hOurDlg,
WSAGetLastError(), "recvfrom()"); }
break; } /* end if
(i_temp == SOCKET_ERROR) */ /* else got a
reply ...*/ wsprintf((LPSTR)prbuf, "Server:
%s\n", (LPSTR) ReplyBuffer);
SetDlgItemText(hOurDlg, IDD_COMMENT, prbuf);
break; } /* end while(1) */
/* Returns the number of bytes written */
long UReadData(SOCKET hSock, HWND hOurDlg, int read_len) {
static char ReadBuf[BUF_SIZE]; static
char SendBuf[512]; struct sockaddr_in
local; /* Local machine address
structure */ int i;
/* General purpose return
code */ long total_time =
0L; /* variable to hold delta t
*/ int tmp, len = 0; int
num_reads = 0; long bytes_read = 0L; long last_time, now,
timeout = 15L; long ltemp; extern int run_cancelled;
BOOL bTemp = TRUE;
SetDlgItemText(hOurDlg,
IDD_COMMENT, "Awaiting the UDP Data ...");
SetDlgItemText(hOurDlg, IDD_HNAME, " ");
time(&now);
time(&last_time); while (last_time + timeout > now) {
time(&now); tmp =
sizeof(local); do { ;
} while (ShoutBlockingHook()); /* Dispatch
messages while available */
if (run_cancelled) {
WSASetLastError(WSAEINTR);
break; /* Non-blocking mode was cancelled */
}
len = recvfrom(hSock, ReadBuf, read_len, 0,
(struct sockaddr *) &local, &tmp);
if (len == SOCKET_ERROR) {
if (h_errno == WSAEWOULDBLOCK) {/* if no
data, read again */
continue; } /* end: if (errno ==
WSAEWOULDBLOCK) */ else {
if (bytes_read) {
wshout_err (hOurDlg,
WSAGetLastError(), "recvfrom()");
} } /* end else */
break; } /* end: if
(len == SOCKET_ERROR) */
if (bTemp) { /* To update
our main display once */ /* Do not use
wsprintf() or you will add an extra char */
_fmemcpy(prbuf, inet_ntoa(local.sin_addr), 4*sizeof(u_long));
SetDlgItemText(hOurDlg, IDD_HNAME, (LPSTR)
prbuf); SetDlgItemText(hOurDlg, IDD_COMMENT,
"Reading UDP Data ..."); bTemp = FALSE;
}
num_reads++;
if (len != SOCKET_ERROR)
bytes_read += len; /*
Print the statistics gathered */
wsprintf((LPSTR)prbuf,"%d\n",num_reads);
SetDlgItemText(hOurDlg, IDD_WRITE, (LPSTR) prbuf);
/* Returns the number of
bytes written */ long TWriteData(SOCKET hSock, HWND hOurDlg, int
send_len) { int counter; static int
DataBuffer[BUF_SIZE]; /* Buffer to hold generated
data */ long total_len = 1024L*1024L; /* Total
# of bytes to generate */ long bytes_sent =
0L; /* Counter of bytes on connection */ int
tmp = 0; /*
holds count for bytes written */ long
write_count = 0L; /* number of
times */
time_t start, end;
/* variables to hold read timing */
long total_time = 0L; /*
variable to hold delta t */ long ltemp = 0L; extern int
run_cancelled;
/* What makes shout unique is that it
generates data* * in memory (as opposed to accessing the
disk). * * This tests the 'raw' speed of the
TCP connection * * as the rate-limiting access
time is eliminated. * * First, generate the
data and place it into an * * array,
data_buffer:
*/
/* Write data on the descriptor like a banshee,
* careful to time the writes and count data * transmitted:
*/
SetDlgItemText(hOurDlg, IDD_COMMENT, "...Sending TCP
Data"); time(&start); while (
bytes_sent < total_len) { /* while still bytes to send... */
do { ;
} while (ShoutBlockingHook()); /* Dispatch
messages if any */
if
(run_cancelled) { WSASetLastError(WSAEINTR);
break; /* Non-blocking mode
was cancelled */ }
/* Calc. time elapsed & stats about any
data sent */ time(&end);
/* exit from the while loop */
break;
} /* end if (tmp == -1) */
write_count++; /* incr.
counter of times written */ bytes_sent +=
tmp; /* total # of bytes placed on connection*/
wsprintf(prbuf,"%ld\n",write_count);
SetDlgItemText(hOurDlg, IDD_WRITE, (LPSTR)
prbuf);
wsprintf(prbuf,"%ld\n",bytes_sent);
SetDlgItemText(hOurDlg, IDD_SENT, (LPSTR) prbuf); } /* end while
*/ time(&end);
if (total_time = (long) difftime(end,
start)) { /* Print the statistics gathered */
wsprintf((LPSTR)prbuf,"%ld\n",total_time);
SetDlgItemText(hOurDlg, IDD_TIME, (LPSTR)
prbuf);
/* Returns the number of bytes written */
long TReadData(SOCKET hSock, HWND hOurDlg, int read_len) {
static char ReadBuf[BUF_SIZE]; SOCKET
hAcceptSock; struct sockaddr_in local; /*
Local machine address structure */ long
total_time = 0L; /* variable to hold delta t
*/ int tmp, len = 0;
int num_reads = 0; long bytes_read = 0L;
long last_time = 0L; long now = 0L; long ltemp;
extern long blocking_option; extern int run_cancelled;
struct linger AcceptLinger;
BOOL running = FALSE;
BOOL bTemp = TRUE;
SetDlgItemText(hOurDlg, IDD_COMMENT, "Awaiting the TCP Data ...");
SetDlgItemText(hOurDlg, IDD_HNAME, " ");
tmp = sizeof(local);
if (!blocking_option) {
hAcceptSock = accept(hSock,(struct sockaddr
FAR *)&local, (int FAR
*)&tmp); } else {
for (; {
do {
;
} while (ShoutBlockingHook()); /* Dispatch
messages if any */
if
(run_cancelled) {
WSASetLastError(WSAEINTR);
break; /* Non-blocking mode was cancelled */
}
hAcceptSock =
accept(hSock,(struct sockaddr FAR *)&local,
(int FAR
*)&tmp); if
(hAcceptSock == INVALID_SOCKET) {
if (h_errno == WSAEWOULDBLOCK)
/* Try
again */
; else
{ /*
Fatal error -- pop out. */
break;
} } /* end if
((hAcceptSock = .. */ else
{ /* Success -- pop out.
*/ break;
} }
/* end for */ } /* end else */
/* Now, read the data as fast as we can until no more to
read */ time(&last_time); do { do
{ ; } while
(ShoutBlockingHook()); /* Dispatch messages while available */
if (run_cancelled) {
WSASetLastError(WSAEINTR);
break; /* Non-blocking mode
was cancelled */ }
len = recv(hAcceptSock, ReadBuf, read_len,
0); if (len == SOCKET_ERROR) {
if (h_errno == WSAEWOULDBLOCK)
continue;
else
break; }
else if (len == 0)
break; num_reads++;
bytes_read += len;
if (bTemp)
{ /* To update our main display once */
/* Do not use wsprintf() or you will add an
extra char */ _fmemcpy(prbuf,
inet_ntoa(local.sin_addr), 4*sizeof(u_long));
SetDlgItemText(hOurDlg, IDD_HNAME, (LPSTR) prbuf);
SetDlgItemText(hOurDlg, IDD_COMMENT, "Reading
TCP Data ..."); bTemp = FALSE;
}
} while ((len !=
0) || (len != SOCKET_ERROR)); time (&now);
if (len
== SOCKET_ERROR) { if ((h_errno ==
WSAESHUTDOWN) || (h_errno == WSAENOTCONN)) {
/* nothing available for read. */
wsprintf((LPSTR)prbuf,
"Connection from %s closed.\n",inet_ntoa(local.sin_addr));
SetDlgItemText(hOurDlg, IDD_COMMENT, prbuf);
} else { /* Other
error */ wshout_err (hOurDlg,
WSAGetLastError(), "recv()"); } }
else if (len == 0) { /* Other side shut
down the connection */ wsprintf((LPSTR)prbuf,
"Connection from %s
closed.\n",inet_ntoa(local.sin_addr));
SetDlgItemText(hOurDlg, IDD_COMMENT, prbuf); }
AcceptLinger.l_onoff = 1; AcceptLinger.l_linger = 0;
ret = setsockopt(hAcceptSock, SOL_SOCKET, SO_LINGER,
(char FAR *) &AcceptLinger,
sizeof(AcceptLinger)); if (ret == SOCKET_ERROR) {
wshout_err (hOurDlg, WSAGetLastError(),
"setsockopt()"); }
ret = closesocket(hAcceptSock);
if (ret == SOCKET_ERROR) { wshout_err
(hOurDlg, WSAGetLastError(), "closesocket()"); }
total_time = (long) difftime(now, last_time); if
(total_time == 0) total_time = 1L; /* Avoid
dividing by zero */
/* * Function: WSAsperror() *
* Description: * * Copies string corresponding to the
error code provided * into buf, maximum length len. Returns
length actually * copied to buffer, or zero if error code is
unknown. * String resources should be present for each error
code * using the value of the code as the string ID (except for
* error = 0, which is mapped to WSABASEERR to keep it with *
the others). The DLL is free to use any string IDs that * are
less than WSABASEERR for its own use. * */ int PASCAL
FAR WSAsperror (HANDLE hInst, /* Instance Handle */
int
errorcode, /* WSA Error Number */
char far * buf, /* Buffer for
error string */
int len) /* Length of buffer */ {
int err_len; /* length of error text */
if (errorcode == 0) /* If error passed is 0, use the */
errorcode = WSABASEERR; /* base resource file number */ if
(errorcode < WSABASEERR) /* If invalid Error code */ return
0; /* return string length of zero */
/* error string from the table in the
Resource file into buffer */ err_len =
LoadString(hInst,errorcode,buf,len);
return (err_len); /* return length of error
string retrieved */
SOCKET
ResolveAndConnectHost(LPSTR lpHostName,HWND hOurDlg,int iproto,
int iSockPort) { struct hostent FAR
*host_ptr; /* Ptr to the host
name */ struct sockaddr_in
dest; /* Addr of target
host */ SOCKET
hSock;
/* The socket to create */ int iSockType;
extern int iTCP; extern int iUDP;
/* Internet family
addressing */ dest.sin_family = PF_INET; if (iproto == iTCP)
{ iSockType = SOCK_STREAM; } else if
(iproto == iUDP) { iSockType = SOCK_DGRAM;
} else { return (SOCKET)
-1; /* Unknown protocol */
}
/* default port to connect to. Must be in network byte
order */ dest.sin_port = htons((u_int)
iSockPort);
/* Start connection process to host
described in 'dest' * *
struct. */ SetDlgItemText(hOurDlg,
IDD_COMMENT, "Connecting ..."); ret=connect(hSock,(struct
sockaddr FAR *)&dest,sizeof(dest));
BOOL FAR PASCAL DialogProc(HWND hOurDlg, WORD message,
WORD wParam, LONG lParam) { FARPROC lpProcAbout; FARPROC
lpProcSettings; long lret; WORD wMajorVersion,
wMinorVersion; char hostnm[64];
/* 包含主机名的工作缓冲区 */
case IDD_CANCEL: if
(running) { /* 停止 */
ret =
WSACancelBlockingCall();
run_cancelled = TRUE; if
(ret == SOCKET_ERROR) {
/* WSANOTINITIALISED or WSAENETDOWN or WSAEINVAL
*/ if
(h_errno == WSAENETDOWN) {
/* Watch out for hAcceptSock! */
/*
close what is left of the connection */
closesocket(sd);
}
}
}
break;
case IDM_EXIT:
ret = WSACleanup();
if (ret == SOCKET_ERROR && h_errno ==
WSAEINPROGRESS){
MessageBox(hOurWnd,
"Data transfer in progress.\nStop transfer
first.",
"WndProc()", MB_OK |
MB_APPLMODAL|MB_ICONINFORMATION);
break; /* 一个套接口正处于阻塞状态 */
}
case WM_COMMAND:
switch (wParam){ case IDS_CLIENT:
/* USer has set to Shout */
CheckThisProgBoxOn(hDlg, IDS_CLIENT);
tClientOrServer = iShout;
SetDlgItemText(hMainDlg, IDD_COHOST,"Foreign
host:"); SetDlgItemText(hMainDlg,
IDD_HNAME,""); break;
case IDS_SERVER: /* USer has set to Listen */
CheckThisProgBoxOn(hDlg, IDS_SERVER);
tClientOrServer = iListen;
SetDlgItemText(hMainDlg,
IDD_COHOST,"Listening to:");
SetDlgItemText(hMainDlg, IDD_HNAME,"[Hit 'Start']");
break; case IDS_TCP:
/* USer has set to TCP */
CheckThisProtoBoxOn(hDlg, IDS_TCP);
temporary_protocol = iTCP;
break; case IDS_UDP:
/* USer has set to UDP */
CheckThisProtoBoxOn(hDlg, IDS_UDP);
temporary_protocol = iUDP;
break; case IDS_BLOCK:
/* User has set to blocking mode */
CheckThisBoxOn(hDlg, IDS_BLOCK);
temporary_option = 0L;
break; case IDS_NOBLOCK:
/* User has set to nonblocking mode */
CheckThisBoxOn(hDlg, IDS_NOBLOCK);
temporary_option = 1L;
break; case IDOK: /*
用户已完成对设置的修改 */ buffer_len =
GetDlgItemInt(hDlg, IDS_BUFFLEN, NULL, 0); if
(buffer_len == 0 || buffer_len > 8192) {
MessageBox(hOurWnd, "Buffer length must be
between 1 and 8K",
"Settings()",
MB_OK | MB_APPLMODAL |
MB_ICONSTOP); return
(FALSE); }
port_no = GetDlgItemInt(hDlg, IDS_PORTNO,
NULL, 0); if (port_no == 0) {
MessageBox(hDlg, "Port
number must be between 0 and 65,535",
"Settings()",
MB_OK |
MB_APPLMODAL | MB_ICONSTOP);
return (FALSE); }
len = buffer_len;
iPortNo = port_no; blocking_option =
temporary_option; iProto =
temporary_protocol; iClientOrServer =
tClientOrServer;
case
IDCANCEL: /* 用户不想改变设置 */
EndDialog(hDlg, TRUE);
return (TRUE);
/* 以下就是我们如何处理“模拟阻塞”-本函数检查消息队列,如果发现需要处理的消息,就返回一个正的值。*/
int ShoutBlockingHook (void) { MSG
msg; /* lets us pull messages
via PeekMessage */ int ret = PeekMessage(&msg, NULL, 0, 0,
PM_REMOVE);
if (ret) { TranslateMessage(&msg);
DispatchMessage(&msg); } return ret; }
/*
全局变量*/ #define SOCK_DISCARD
9 /* use the UDP ttytst source port for test */
#define SOCK_SHOUT 32766 /*
TCP port used for SHOUT & LISTEN */
#define BUF_SIZE 8192 #define
WRITE_TIMER 1
/* 函数原型 */ int PASCAL
WinMain(HANDLE, HANDLE, LPSTR, int); long FAR PASCAL
ShoutWndProc(HWND, WORD, WORD, LONG); BOOL FAR PASCAL
About(HWND, WORD, WORD, LONG); BOOL FAR PASCAL DialogProc(HWND,
WORD, WORD, LONG); BOOL FAR PASCAL Settings(HWND, WORD, WORD,
LONG); BOOL InitApp(HANDLE); void CheckThisBoxOn(HWND, int);
void CheckThisProtoBoxOn(HWND, int); void
CheckThisProgBoxOn(HWND, int); void ClearBoxes(HWND); SOCKET
ResolveAndConnectHost(LPSTR, HWND, int, int); SOCKET
GetSocketAndBind(HWND, int, int); long UWriteData(SOCKET, HWND,
int); long UReadData(SOCKET, HWND, int); long
TWriteData(SOCKET, HWND, int); long TReadData(SOCKET, HWND,
int); int ShoutBlockingHook (void); int PASCAL FAR
WSAsperror (HANDLE, int, char far *, int); void wshout_err
(HWND, int, char far *);
/*
* 错误描述字符串表 * 用于WSAsperror()函数 */ STRINGTABLE
BEGIN WSABASEERR, "[0] No Error" WSAEINTR, "[10004]
Interrupted system call" WSAEBADF, "[10009] Bad file number"
WSAEACCES, "[10013] Permission denied" WSAEFAULT, "[10014]
Bad address" WSAEINVAL, "[10022] Invalid argument"
WSAEMFILE, "[10024] Too many open files" WSAEWOULDBLOCK,
"[10035] Operation would block" WSAEINPROGRESS, "[10036]
Operation now in progress" WSAEALREADY, "[10037] Operation
already in progress" WSAENOTSOCK, "[10038] Socket operation on
non-socket" WSAEDESTADDRREQ, "[10039] Destination address
required" WSAEMSGSIZE, "[10040] Message too long"
WSAEPROTOTYPE, "[10041] Protocol wrong type for socket"
WSAENOPROTOOPT, "[10042] Bad protocol option"
WSAEPROTONOSUPPORT, "[10043] Protocol not supported"
WSAESOCKTNOSUPPORT, "[10044] Socket type not supported"
WSAEOPNOTSUPP, "[10045] Operation not supported on socket"
WSAEPFNOSUPPORT, "[10046] Protocol family not supported"
WSAEAFNOSUPPORT, "[10047] Address family not supported by
protocol family" WSAEADDRINUSE, "[10048] Address already in use"
WSAEADDRNOTAVAIL, "[10049] Can't assign requested address"
WSAENETDOWN, "[10050] Network is down" WSAENETUNREACH,
"[10051] Network is unreachable" WSAENETRESET, "[10052] Net
dropped connection or reset" WSAECONNABORTED, "[10053] Software
caused connection abort" WSAECONNRESET, "[10054] Connection
reset by peer" WSAENOBUFS, "[10055] No buffer space available"
WSAEISCONN, "[10056] Socket is already connected"
WSAENOTCONN, "[10057] Socket is not connected" WSAESHUTDOWN,
"[10058] Can't send after socket shutdown" WSAETOOMANYREFS,
"[10059] Too many references, can't splice" WSAETIMEDOUT,
"[10060] Connection timed out" WSAECONNREFUSED, "[10061]
Connection refused" WSAELOOP, "[10062] Too many levels of
symbolic links" WSAENAMETOOLONG, "[10063] File name too long"
WSAEHOSTDOWN, "[10064] Host is down" WSAEHOSTUNREACH,
"[10065] No Route to Host" WSAENOTEMPTY, "[10066] Directory not
empty" WSAEPROCLIM, "[10067] Too many processes" WSAEUSERS,
"[10068] Too many users" WSAEDQUOT, "[10069] Disc Quota
Exceeded" WSAESTALE, "[10070] Stale NFS file handle"
WSAEREMOTE, "[10071] Too many levels of remote in path"
WSASYSNOTREADY, "[10091] Network SubSystem is unavailable"
WSAVERNOTSUPPORTED, "[10092] WINSOCK DLL Version out of range"
WSANOTINITIALISED, "[10093] Successful WSASTARTUP not yet
performed" WSAHOST_NOT_FOUND, "[11001] Host not found"
WSATRY_AGAIN, "[11002] Non-Authoritative Host not found"
WSANO_RECOVERY, "[11003] Non-Recoverable errors: FORMERR,
REFUSED, NOTIMP" WSANO_DATA, "[11004] Valid name, no data record
of requested type" END
/* Returns the number of bytes written */
long UWriteData(SOCKET hSock, HWND hOurDlg, int send_len) {
int counter; static int DataBuffer[BUF_SIZE]; /* Buffer to
hold generated data */ static char
ReplyBuffer[512]; /* Buffer to hold any reply rcvd */ long
bytes_sent = 0L; /* Counter of bytes on
connection */ long total_len = 1024L*1024L; /*
Total # of bytes to generate */ time_t start,
end; /* variables to hold read
timing */ long total_time =
0L; /* variable to hold delta t
*/ long write_count = 0L; /* number of
times */ long tmp =
0L; /* holds count for bytes
written */ long ltemp = 0L; int i_temp;
extern int run_cancelled;
/* What makes shout unique is that it generates data* *
in memory (as opposed to accessing the disk). *
* This tests the 'raw' speed of the TCP
connection * * as the rate-limiting access
time is eliminated. * * First, generate the
data and place it into an * * array,
data_buffer:
*/
/* Write data on the descriptor like a banshee,
* careful to time the writes and count data * transmitted:
*/
SetDlgItemText(hOurDlg, IDD_COMMENT, "Sending UDP
Data ..."); time( &start ); while
(bytes_sent < total_len){/* while still bytes to send */
do { ;
} while (ShoutBlockingHook()); /* Dispatch
messages if any */
if
(run_cancelled) { WSASetLastError(WSAEINTR);
break; /* Non-blocking mode
was cancelled */ }
tmp = send(hSock, (char FAR *)
&DataBuffer, send_len, 0); if (tmp ==
SOCKET_ERROR) { if (h_errno ==
WSAEWOULDBLOCK) /* if no data, read again */
continue; else {
wshout_err (hOurDlg,
WSAGetLastError(), "send()"); }
/* Calc. time elapsed
& stats about any data sent */
time(&end); if (total_time = (long)
difftime(end, start)) { /*
Print the statistics gathered */
wsprintf((LPSTR)prbuf,"%ld\n",write_count);
SetDlgItemText(hOurDlg,
IDD_WRITE, (LPSTR) prbuf);