|
![]() | 作者: xiaoxingchi [xiaoxingchi]
![]() |
登录 |
第三章 Windows Sockets 1.1应用实例 在本章中,作者的实际工作为背景,给出了一个使用Windows Sockets 1.1编程的具体例子。并对这个例子作了详细的分析。这个例子在Windows 3.1、Windows Sockets 1.1和BSD OS for PC 2.0(BSD UNIX微机版)环境下调试通过。 3.1 套接口网络编程原理 套接口有三种类型:流式套接口,数据报套接口及原始套接口. 流式套接口定义了一种可靠的面向连接的服务,实现了无差错无重复的顺序数据传输.数据报套接口定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠,无差错.原始套接口允许对低层协议如IP或ICMP直接访问,主要用于新的网络协议实现的测试等. 无连接服务器一般都是面向事务处理的,一个请求一个应答就完成了客户程序与服务程序之间的相互作用。若使用无连接的套接口编程,程序的流程可以用图3-1表示。 面向连接服务器处理的请求往往比较复杂,不是一来一去的请求应答所能解决的,而且往往是并发服务器。使用面向连接的套接口编程,可以通过图3-1来表示:其时序。 套接口工作过程如下:服务器首先启动,通过调用socket()建立一个套接口,然后调用bind()将该套接口和本地网络地址联系在一起,再调用listen()使套接口做好侦听的准备,并规定它的请求队列的长度,之后就调用accept()来接收连接.客户在建立套接口后就可调用connect()和服务器建立连接.连接一旦建立,客户机和服务器之间就可以通过调用read()和write()来发送和接收数据.最后,待数据传送结束后,双方调用close()关闭套接口. 3.2 Windows Sockets编程原理 由于Windows的基于消息的特点,WINSOCK和BSD套接口相比,有如下一些新的扩充: 1.异步选择机制 异步选择函数WSAAsyncSelect()允许应用程序提名一个或多个感兴趣的网络事件,如FD_READ,FD_WRITE,FD_CONNECT,FD_ACCEPT等等代表的网络事件.当被提名的网络事件发生时,Windows应用程序的窗口函数将收到一个消息.这样就可以实现事件驱动了. 2.异步请求函数 异步请求函数允许应用程序用异步方式获得请求的信息,如WSAAsyncGetXByY()类函数. 这些函数是对BSD标准函数的扩充.函数WSACancelAsyncRequest()允许用户中止一个正在执行的异步请求. 3.阻塞处理方法 WINSOCK提供了"钩子函数"负责处理Windows消息,使Windows的消息循环能够继续.WINSOCK提供了两个函数(WSASetBlockingHook()和WSAUnhookBlockingHook())让应用程序设置或取消自己的"钩子函数".函数WSAIsBlocking()可以检测是否阻塞,函数WSACancelBlockingCall()可以取消一个阻塞的调用. 4.错误处理 WINSOCK提供了两个WSAGetLastError()和WSASetLastError()来获取和设置最近错误号. 5.启动和终止 由于Windows Sockets的服务是以动态连接库WINSOCK.DLL形式实现的,所以必须要先调用WSAStartup()函数对Windows Sockets DLL进行初始化,协商WINSOCK的版本支持,并分配必要的资源.在应用程序关闭套接口后,还应调用WSACleanup()终止对Windows Sockets DLL的使用,并释放资源,以备下一次使用. 在这些函数中,实现Windows网络实时通信的关键是异步选择函数WSAAsyncSelect()的使用. 用法及详细说明参见第5.3.7. 3.3 Windows Sockets与UNIX套接口编程实例 下面是一个简单的基于连接的点对点实时通信程序.它由两部分组成,服务器在主机UNIX下直接运行, 客户机在Windows下运行. 3.3.1 SERVER介绍 由于SERVER是在UNIX下运行的,它对套接口的使用都是BSD的标准函数,程序也比较简单, 只有一段程序,下面简要解释一下. 首先,建立自己的套接口.在互连网的进程通信中,全局标识一个进程需要一个被称为"半相关"的三元组(协议,本地主机地址,本地端口号)来描述,而一个完整的进程通信实例则需要一个被称为"相关"的五元组(协议, 本地主机地址,本地端口号,远端主机地址,远端端口号)来描述. s=socket(AF_INET, SOCK_STREAM, 0) 该函数建立指定地址格式,数据类型和协议下的套接口,地址格式为AF_INET(唯一支持的格式),数据类型SOCK_STREAM表示建立流式套接口,参数三为0,即协议缺省. bind(s, (struct sockaddr *)&server, sizeof(server)) 该函数将建立服务器本地的半相关,其中,server是sockaddr_in结构,其成员描述了本地端口号和本地主机地址,经过bind()将服务器进程在网上标识出来. 然后,建立连接.先是调用listen()函数表示开始侦听.再通过accept()调用等待接收连接. listen(s,1)表示连接请求队列长度为1,即只允许有一个请求,若有多个请求,则出现错误,给出错误代码WSAECONNREFUSED. ns = accept(s, (struct sockaddr *)&client, &namelen)) accept()阻塞(缺省)等待请求队列中的请求,一旦有连接请求来,该函数就建立一个和s有相同属性的新的套接口.client也是一个sockaddr_in结构,连接建立时填入请求连接的套接口的半相关信息. 接下来,就可以接收和发送数据了. recv(ns,buf,1024,0) send(ns,buf,pktlen,0) 上面两个函数分别负责接收和发送数据,recv从ns(建立连接的套接口)接收数据放入buf中,send则将buf中数据发送给ns.至于第四个参数,表示该函数调用方式,可选择MSG_DONTROUTE和MSG_OOB, 0表示缺省. 最后,关闭套接口. close(ns); close(s); 3.3.2 CLIENT介绍 客户端是在Windows上运行的,使用了一些Windows Sockets的扩展函数,稍微复杂一些.包括了.RC和.C两个文件,其中的主窗口函数ClientProc()是程序的主要部分,下面简单解释一下. 首先,是在WinMain()中建立好窗口后,即向主窗口函数发一条自定义的WM_USER消息, 做相关的准备工作.在主窗口函数中,一接收到WM_USER消息,首先调用WSAStartup()函数初始化Windows Sockets DLL,并检查版本号.如下: Status = WSAStartup(VersionReqd, lpmyWSAData); 其中,VersionReqd描述了WINSOCK的版本(这里为1.1版),lpmyWSAData指向一个WSADATA结构,该结构描述了Windows Sockets的实现细节. WSAStartup()之后,进程通过主机名(运行时命令行参数传入)获取主机地址,如下: hostaddr = gethostbyname(server_address); hostaddr指向hostent结构,内容参见5.2.1. 然后,进程就不断地消息循环,等待用户通过菜单选择"启动".这时,通过调用Client()来启动套接口.在Client()中,首先也是调用socket()来建立套接口.如下: if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { AlertUser(hWnd, "Socket Failed"); return (FALSE); } 紧接着,调用WSAAsyncSelect()函数提名FD_CONNECT网络事件,如下: if (!SetSelect(hWnd, FD_CONNECT)) return (FALSE); SetSelect()主要就是调用WSAASyncSelect(),让Windows Sockets DLL在侦测到连接建立时,就发送一条UM_SOCK的自定义消息,使消息循环继续下去.如下: BOOL SetSelect(HWND hWnd, long lEvent) { if (WSAAsyncSelect(s, hWnd, UM_SOCK, lEvent) == SOCKET_ERROR) { AlertUser(hWnd, "WSAAsyncSelect Failure."); return (FALSE); } return (TRUE); } 为建立连接,必须马上调用connect()如下,由于先调用了WSAASyncSelect(),connect()便是非阻塞调用.进程发出连接请求后就不管了,当连接建立好后,WINSOCK DLL自动发一条消息给主窗口函数,以使程序运行下去. connect(s, (struct sockaddr FAR *)&dst_addr, sizeof(dst_addr)); 窗口函数在收到UM_SOCK消息后,判断是由哪个网络事件引起的,第一次,必然是由连接事件引起的,这样,就会执行相应的程序段,同样调用SetSelect()来提名FD_WRITE事件.希望在套接口可发送数据时接到消息.在收到FD_WRITE消息时,先调用send()发送数据,再调用SetSelect()来提名FD_READ事件, 希望在套接口可接收数据是接到消息.在收到FD_READ消息时,先调用recv()来接收数据再提名FD_WRITE事件,如此循环下去.直到发生连接关闭的事件FD_CLOSE,这时就调用WSAAsyncSelect(s,hWnd,0,0)来停止异步选择.在窗口函数接到WM_DESTROY消息时(即关闭窗口之前),先调用closesocket()(作用同UNIX 中的close())来关闭套接口,再调用WSACleanup()终止Windows Sockets DLL,并释放资源. 3.3.3 源程序清单 程序1:CLIENT.RC ClientMenu MENU BEGIN POPUP "&Server" BEGIN MENUITEM "&Start...", 101 MENUITEM "&Exit", 102 END END 程序2:CLIENT.C #define USERPORT 10001 #define IDM_START 101 #define IDM_EXIT 102 #define UM_SOCK WM_USER + 0X100 #include <alloc.h> #include <mem.h> #include <windows.h> #include <winsock.h> #define MAJOR_VERSION 1 #define MINOR_VERSION 2 #define WSA_MAKEWORD(x,y) ((y)*256+(x)) HANDLE hInst; char server_address[256] = {0}; char buffer[1024]; char FAR * lpBuffer = &buffer[0]; SOCKET s = 0; struct sockaddr_in dst_addr; struct hostent far *hostaddr; struct hostent hostnm; struct servent far *sp; int count = 0; BOOL InitApplication(HINSTANCE hInstance); long FAR PASCAL ClientProc(HWND hWnd, unsigned message, UINT wParam, LONG lParam); void AlertUser(HWND hWnd, char *message); BOOL Client(HWND hWnd); BOOL ReceivePacket(HWND hWnd); BOOL SetSelect(HWND hWnd, long lEvent); BOOL SendPacket(HWND hWnd, int len); int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { HWND hWnd; MSG msg; lstrcpy((LPSTR)server_address, lpCmdLine); if (!hPrevInstance) if (!InitApplication(hInstance)) return (FALSE); hInst = hInstance; hWnd = CreateWindow("ClientClass", "Windows ECHO Client", WS_OVERLAPPEDWINDOW,\ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL,\ hInstance, NULL); if (!hWnd) return (FALSE); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); PostMessage(hWnd, WM_USER, (WPARAM)0, (LPARAM)0); while (GetMessage(&msg, NULL, NULL, NULL)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (msg.wParam); } BOOL InitApplication(HINSTANCE hInstance) { WNDCLASS WndClass; char *szAppName = "ClientClass"; // fill in window class information WndClass.lpszClassName = (LPSTR)szAppName; WndClass.hInstance = hInstance; WndClass.lpfnWndProc = ClientProc; WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); WndClass.hIcon = LoadIcon(hInstance, NULL); WndClass.lpszMenuName = "ClientMenu"; WndClass.hbrBackground = GetStockObject(WHITE_BRUSH); WndClass.style = CS_HREDRAW | CS_VREDRAW; WndClass.cbClsExtra = 0; WndClass.cbWndExtra = 0; // register the class if (!RegisterClass(&WndClass)) return(FALSE); return(TRUE); } long FAR PASCAL ClientProc(HWND hWnd, unsigned message, UINT wParam, LONG lParam) { int length, i; WSADATA wsaData; int Status; switch (message) { case WM_USER: { WORD wMajorVersion, wMinorVersion; LPWSADATA lpmyWSAData; WORD VersionReqd; int ret; wMajorVersion = MAJOR_VERSION; wMinorVersion = MINOR_VERSION; VersionReqd = WSA_MAKEWORD(wMajorVersion,wMinorVersion); lpmyWSAData = (LPWSADATA)malloc(sizeof(WSADATA)); Status = WSAStartup(VersionReqd, lpmyWSAData); if (Status != 0) { AlertUser(hWnd, "WSAStartup() failed\n"); PostQuitMessage(0); } hostaddr = gethostbyname(server_address); if (hostaddr == NULL) { AlertUser(hWnd, "gethostbyname ERROR!\n"); WSACleanup(); PostQuitMessage(0); } _fmemcpy(&hostnm, hostaddr, sizeof(struct hostent)); } break; case WM_COMMAND: switch (wParam) { case IDM_START: if (!Client(hWnd)) { closesocket(s); AlertUser(hWnd, "Start Failed"); } break; case IDM_EXIT: // WSACleanup(); PostQuitMessage(0); break; } break; case UM_SOCK: switch (lParam) { case FD_CONNECT: if (!SetSelect(hWnd, FD_WRITE)) closesocket(s); break; case FD_READ: if (!ReceivePacket(hWnd)) { AlertUser(hWnd, "Receive Packet Failed.\n"); closesocket(s); break; } if (!SetSelect(hWnd, FD_WRITE)) closesocket(s); break; case FD_WRITE: for (i = 0; i < 1024; i ++) buffer[i] = (char)'A' + i % 26; length = 1024; if (!SendPacket(hWnd, length)) { AlertUser(hWnd, "Packet Send Failed!\n"); closesocket(s); break; } if (!SetSelect(hWnd, FD_READ)) closesocket(s); break; case FD_CLOSE: if (WSAAsyncSelect(s, hWnd, 0, 0) == SOCKET_ERROR) AlertUser(hWnd, "WSAAsyncSelect Failed.\n"); break; default: if (WSAGETSELECTERROR(lParam) != 0) { AlertUser(hWnd, "Socket Report Failure."); closesocket(s); break; } break; } break; case WM_DESTROY: closesocket(s); WSACleanup(); PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, message, wParam, lParam)); } return(NULL); } void AlertUser(HWND hWnd, char *message) { MessageBox(hWnd, (LPSTR)message, "Warning", MB_ICONEXCLAMATION); return; } BOOL Client(HWND hWnd) { memset(&dst_addr,'\0', sizeof (struct sockaddr_in)); _fmemcpy((char FAR *)&dst_addr.sin_addr,(char FAR *)hostnm.h_addr,hostnm.h_length); dst_addr.sin_family = hostnm.h_addrtype; dst_addr.sin_port = htons(USERPORT); if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { AlertUser(hWnd, "Socket Failed"); return (FALSE); } if (!SetSelect(hWnd, FD_CONNECT)) return (FALSE); connect(s, (struct sockaddr FAR *)&dst_addr, sizeof(dst_addr)); return (TRUE); } BOOL ReceivePacket(HWND hWnd) { HDC hDc; int length; int i1,i2,i3; char line1[255], line2[255], line3[255]; count ++; if ((length = recv(s, lpBuffer, 1024, 0)) == SOCKET_ERROR) return (FALSE); if (length == 0) return (FALSE); if (hDc = GetDC(hWnd)) { i1 = wsprintf((LPSTR)line1, "TCP Echo Client No.%d", count); i2 = wsprintf((LPSTR)line2, "Receive %d bytes",length); i3 = wsprintf((LPSTR)line3, "Those are:%c, %c, %c, %c, %c, %c",buffer[0],buffer[1],buffer[2],buffer[100],buffer[1000],buffer[1023]); TextOut(hDc, 10, 2, (LPSTR)line1, i1); TextOut(hDc, 10, 22, (LPSTR)line2, i2); TextOut(hDc, 10, 42, (LPSTR)line3, i3); ReleaseDC(hWnd, hDc); } return (TRUE); } BOOL SetSelect(HWND hWnd, long lEvent) { if (WSAAsyncSelect(s, hWnd, UM_SOCK, lEvent) == SOCKET_ERROR) { AlertUser(hWnd, "WSAAsyncSelect Failure."); return (FALSE); } return (TRUE); } BOOL SendPacket(HWND hWnd, int len) { int length; if ((length = send(s, lpBuffer, len, 0)) == SOCKET_ERROR) return (FALSE); else if (length != len) { AlertUser(hWnd, "Send Length NOT Match!"); return (FALSE); } return (TRUE); } 程序3:SERVER.C #include <sys/types.h> #include <sys/mntent.h> #include <netinet/in.h> #include <sys/socket.h> #include <arpa/inet.h> #define USERPORT 10001 #define HOST_IP_ADDR "192.1.1.2" main(int argc, char **argv) { char buf[1024]; struct sockaddr_in client; struct sockaddr_in server; int s; int ns; int namelen; int pktlen; if ((s=socket(AF_INET, SOCK_STREAM, 0))<0) { perror("Socket()"); return; } bzero((char *)&server,sizeof(server)); server.sin_family = AF_INET; server.sin_port = htons(USERPORT); server.sin_addr.s_addr = INADDR_ANY; if (bind(s, (struct sockaddr *)&server, sizeof(server))<0) { perror("Bind()"); return; } if (listen(s,1)!=0) { perror("Listen()"); return; } namelen = sizeof(client); if ((ns = accept(s, (struct sockaddr *)&client, &namelen)) ==-1) { perror("Accept()"); return; } for (;;) { if ((pktlen = recv(ns,buf,1024,0))<0) { perror("Recv()"); break; } else if (pktlen == 0) { printf("Recv():return FAILED,connection is shut down!\n"); break; } else printf("Recv():return SUCCESS,packet length = %d\n",pktlen); sleep(1); if (send(ns,buf,pktlen,0)<0) { perror("Send()"); break; } else printf("Send():return SUCCESS,packet length = %d\n",pktlen); } close(ns); close(s); printf("Server ended successfully\n"); } 3.4 另一个精巧的应用程序实例-wshout 在本节中,我们通过一个经过精心选择的例子,进一步讨论一下Windows Sockets编程技术。例如如何编制客户机或服务器程序,如何应用TCP有连接服务(流式套接口)或UDP无连接服务(数据报套接口),如何进行阻塞或非阻塞方式的套接口操作等等,这些都是经常碰到的问题。接下来要介绍的wshout程序,可以通过灵活地设置不同选项来达到上述应用情况的任意组合,从而基本覆盖了应用Windows Sockets编程所可能碰到的问题,具有很好的研究参考价值。 由于该程序思路清晰,结构精良,所以我们不打算很详细地剖析每一个语句,而只是简要介绍一下整个程序的逻辑结构,并在源程序中加入适当的注释。我们相信,任何具有基本C语言和Windows编程经验的读者,都能很轻松地读懂绝大部分内容。经过仔细咀嚼和推敲后,更能得到一些编写优质程序的灵感。 该程序在FTP公司的PCTCP支撑环境下调试通过,不过只要读者拥有任何符合Windows Sockets 1.1规范的实现,也能顺利执行该程序。 3.4.1 源程序目录 1. wshout.c wshout主程序 2. wshout.h wshout头文件 3. wshout.rc wshout资源文件 4. ushout.c UDP客户机程序 5. ulisten.c UDP服务器程序 6. tshout.c TCP客户机程序 7. tlisten.c TCP服务器程序 8. errno.c 获取WSAE*错误描述字符串程序 9. resolve.c 客户机/服务器启动程序 在编译本程序时,笔者用的是BC3.1,只需做一个PRJ工程文件,将上述.c文件及winsock.lib包括进来就行了。请注意winsock.h应在include目录或当前目录中,winsock.lib可利用winsock.dll通过implib工具来建立。如果读者使用其他的编译器,可自行作相应的调整,在此不再赘述。 3.4.2 程序逻辑结构 3.4.3 源程序清单及注释 3.4.3.1 wshout.c清单 /* * 文件名: WSHOUT.C */ /* MSC Include files: */ #include <stdio.h> #include <io.h> #include <string.h> #include <stdlib.h> #include <time.h> #include "wshout.h" #define MAJOR_VERSION 1 #define MINOR_VERSION 2 #define WSA_MAKEWORD(x,y) ((y) * 256 + (x)) /* HI:Minor, LO:Major */ HANDLE hInst; /* 进程实例句柄 */ HWND hOurWnd; /* 主窗口句柄 */ HWND hMainDlg; /* 主对话框句柄 */ int ret; /* 工作变量 */ char prbuf[PRBUF_LEN]; /* 用于显示文本的工作缓冲区 */ SOCKET sd; /* 用于监听连接的套接口描述字 */ long temporary_option = 0L; /* 缺省为阻塞模式 */ long blocking_option = 0L; /* 阻塞模式的全局标识 */ int run_cancelled = 0; /* 指示何时按下了取消按钮 */ int len = 1024; /* 一次写的字节数 */ BOOL running = FALSE; /* 程序的运行状态 */ const int iTCP = 1; /* 指定为TCP Shout */ const int iUDP = 2; /* 指定为UDP Shout */ int iProto = 1; /* 缺省为TCP Shout */ int iPortNo = SOCK_SHOUT; int temporary_protocol = 1; /* 在Settings()中使用 */ int iShout = 1; int iListen = 2; int iClientOrServer = 1; /* 缺省为Shout(客户机) */ int tClientOrServer = 1; /* 在Settings()中使用 */ char HostModeBuf[20];/* 保存模式字符串 */ WORD VersionReqd; LPWSADATA lpmyWSAData; int PASCAL WinMain (HANDLE hInstance,HANDLE hPrevInstance,LPSTR lpCmdLine,int nCmdShow) { HWND hWnd; MSG msg; BOOL InitApp(HANDLE); if (!hPrevInstance) if (!InitApp(hInstance)) return (NULL); hInst = hInstance; hWnd = CreateWindow("MainMenu", "Windows Shout", WS_OVERLAPPEDWINDOW | WS_SYSMENU | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); if (!hWnd) return (NULL); hOurWnd = hWnd; while (GetMessage(&msg, NULL, NULL, NULL)) { TranslateMessage(&msg); /* 翻译虚拟键码 */ DispatchMessage(&msg); } return (msg.wParam); } BOOL InitApp(HANDLE hInstance) { HANDLE hMemory; PWNDCLASS pWndClass; BOOL bSuccess; hMemory = LocalAlloc(LPTR, sizeof(WNDCLASS)); pWndClass = (PWNDCLASS) LocalLock(hMemory); pWndClass->hCursor = LoadCursor(NULL, IDC_ARROW); pWndClass->hIcon = LoadIcon(hInstance, (LPSTR) "SHOUT"); pWndClass->lpszMenuName = (LPSTR) "MainMenu"; pWndClass->lpszClassName = (LPSTR) "MainMenu"; pWndClass->hbrBackground = GetStockObject(WHITE_BRUSH); pWndClass->hInstance = hInstance; pWndClass->style = NULL; pWndClass->lpfnWndProc = ShoutWndProc; bSuccess = RegisterClass(pWndClass); LocalUnlock(hMemory); LocalFree(hMemory); return (bSuccess); } long FAR PASCAL ShoutWndProc(HWND hWnd, WORD message,WORD wParam, LONG lParam) { FARPROC lpDialogBoxProc; switch (message){ case WM_CREATE: /* Put up the dialog box */ lpDialogBoxProc = MakeProcInstance(DialogProc, hInst); DialogBox (hInst, (LPSTR) "MainDialog", hWnd, lpDialogBoxProc) ; FreeProcInstance(lpDialogBoxProc); PostMessage(hWnd, WM_DESTROY, 0, 0L); break; case WM_DESTROY: PostQuitMessage(0); break; default: return(DefWindowProc(hWnd, message, wParam, lParam)); } return NULL; } BOOL FAR PASCAL DialogProc(HWND hOurDlg, WORD message, WORD wParam, LONG lParam) { FARPROC lpProcAbout; FARPROC lpProcSettings; long lret; WORD wMajorVersion, wMinorVersion; char hostnm[64]; /* 包含主机名的工作缓冲区 */ switch (message) { case WM_INITDIALOG: /* 选择缺省主机 */ SetDlgItemText(hOurDlg, IDD_HNAME, ""); SendDlgItemMessage(hOurDlg, /* 对话框句柄 */ IDD_HNAME, /* 向何处发送msg */ EM_SETSEL, /* 选择字符 */ NULL, /* 附加信息 */ MAKELONG(0, 0x7fff)); /* 全部内容 */ SetFocus(GetDlgItem(hOurDlg, IDD_HNAME)); /* 初始化 */ hMainDlg = hOurDlg; /* 保存自己的窗口句柄 */ SetDlgItemText(hOurDlg, IDD_COHOST,"Shout to:"); wMajorVersion = MAJOR_VERSION; wMinorVersion = MINOR_VERSION; VersionReqd=WSA_MAKEWORD(wMajorVersion, wMinorVersion); lpmyWSAData = (LPWSADATA)_calloc(1, sizeof(WSADATA)); ret = WSAStartup(VersionReqd, lpmyWSAData); if (ret != 0){ wshout_err (hOurDlg, WSAGetLastError(), "WSAStartup()"); } return (TRUE); case WM_CLOSE: PostMessage(hOurDlg, WM_COMMAND, IDM_EXIT, 0L); break; case WM_SYSCOMMAND: SendMessage(hOurWnd, message, wParam, lParam); break; case WM_COMMAND: switch (wParam) { case IDD_CONNECT: /* 按下连接按钮 */ case IDM_START: /* 选择了Start菜单项 */ run_cancelled = FALSE; /* 不能重入 */ if (running){ MessageBox(hOurWnd,"Shout is already running !", "Shout", MB_OK | MB_APPLMODAL | MB_ICONEXCLAMATION); return FALSE; } ClearBoxes(hOurDlg); running = TRUE; if (iClientOrServer == iShout) { /* 确保有主机名 */ if (GetDlgItemText (hOurDlg, IDD_HNAME, hostnm, 80) < 2) { MessageBeep(0); SetDlgItemText(hOurDlg, IDD_COMMENT,"No hostname specified"); running = FALSE; break; } sd = ResolveAndConnectHost((char FAR *)hostnm,hOurDlg,iProto, iPortNo); if (sd == SOCKET_ERROR) {/* 无法创建套接口 */ running = FALSE; break; } } else { sd = GetSocketAndBind(hOurDlg, iProto, iPortNo); if (sd == SOCKET_ERROR) { running = FALSE; break; } } /* Set the I/O mode of the socket */ if (blocking_option) { lret = 1L; /* 非阻塞模式 */ ioctlsocket(sd, FIONBIO, (u_long FAR *) &lret); } else { lret = 0L; /* 阻塞模式 */ ioctlsocket(sd, FIONBIO, (u_long FAR *) &lret); } if (iClientOrServer == iShout) { /* SHOUT */ /* 产生数据并写入套接口 */ if (iProto == iTCP) lret = TWriteData(sd, hOurDlg, len); else /* UDP */ lret = UWriteData(sd, hOurDlg, len); } else { /* LISTEN */ if (iProto == iTCP) lret = TReadData(sd,hOurDlg, len); else /* UDP */ lret = UReadData(sd,hOurDlg, len); } closesocket(sd); running = FALSE; break; 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; /* 一个套接口正处于阻塞状态 */ } _free((char NEAR *) lpmyWSAData); EndDialog(hOurDlg, TRUE) ; /* 退出 */ break; case IDM_ABOUT: lpProcAbout = MakeProcInstance(About, hInst); DialogBox(hInst, "AboutBox", hOurDlg, lpProcAbout); FreeProcInstance(lpProcAbout); break; case IDM_SETTINGS: lpProcSettings = MakeProcInstance(Settings, hInst); DialogBox(hInst, "SettingsDialog", hOurDlg, lpProcSettings); FreeProcInstance(lpProcSettings); break; default: break; } /* switch (wParam) */ break; } /* switch (message) */ return FALSE; } /* 此函数处理About对话框 */ BOOL FAR PASCAL About(HWND hDlg, WORD message, WORD wParam, LONG lParam) { char tempBuf[15]; switch (message) { case WM_INITDIALOG: SetDlgItemText(hDlg, IDA_COPYRIGHT,(LPSTR)lpmyWSAData->szDescription); wsprintf(tempBuf, "%d.%2d\n",MAJOR_VERSION, MINOR_VERSION); SetDlgItemText(hDlg, IDA_APP_VERSION, (LPSTR) tempBuf); wsprintf(tempBuf, "%d.%2d\n", lpmyWSAData->wVersion%256,lpmyWSAData->wVersion/256); SetDlgItemText (hDlg, IDA_DLL_VERSION, (LPSTR) tempBuf); return (FALSE); case WM_COMMAND: if (wParam == IDOK || wParam == IDCANCEL) { EndDialog(hDlg, TRUE); return (TRUE); } break; } return (FALSE); } /* 此函数处理Settings 对话框 */ BOOL FAR PASCAL Settings(HWND hDlg, WORD message, WORD wParam, LONG lParam) { int buffer_len = len; int port_no = iPortNo; switch (message) { case WM_INITDIALOG: /* Select a default send() buffer length */ SetDlgItemInt(hDlg, IDS_BUFFLEN, len, 0); /* Select a default port number */ SetDlgItemInt(hDlg, IDS_PORTNO, iPortNo, 0); if (iClientOrServer == iShout) /* 程序类型 */ CheckThisProgBoxOn(hDlg, IDS_CLIENT); else CheckThisProgBoxOn(hDlg, IDS_SERVER); if (iProto == iTCP) /* 协议类型 */ CheckThisProtoBoxOn(hDlg, IDS_TCP); else CheckThisProtoBoxOn(hDlg, IDS_UDP); if (!blocking_option) /* 阻塞模式 */ CheckThisBoxOn(hDlg, IDS_BLOCK); else CheckThisBoxOn(hDlg, IDS_NOBLOCK); SendDlgItemMessage(hDlg, /* dialog handle */ IDS_PORTNO, /* where to send msg */ EM_SETSEL, /* select characters */ NULL, /* additional info */ MAKELONG(0, 0x7fff)); /* entire contents */ SendDlgItemMessage(hDlg, /* dialog handle */ IDS_BUFFLEN, /* where to send msg */ EM_SETSEL, /* select characters */ NULL, /* additional info */ MAKELONG(0, 0x7fff)); /* entire contents */ SetFocus(GetDlgItem(hDlg, IDS_BUFFLEN)); return (TRUE); 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); default: break; } default: break; } return (FALSE); } void CheckThisBoxOn(HWND hDlg, int ButtonID) { switch (ButtonID) { case IDS_BLOCK: CheckDlgButton(hDlg, IDS_BLOCK, 1); CheckDlgButton(hDlg, IDS_NOBLOCK, 0); break; case IDS_NOBLOCK: CheckDlgButton(hDlg, IDS_BLOCK, 0); CheckDlgButton(hDlg, IDS_NOBLOCK, 1); break; default: break; } return; } void CheckThisProtoBoxOn(HWND hDlg, int ButtonID) { switch (ButtonID) { case IDS_TCP: CheckDlgButton(hDlg, IDS_TCP, 1); CheckDlgButton(hDlg, IDS_UDP, 0); break; case IDS_UDP: CheckDlgButton(hDlg, IDS_TCP, 0); CheckDlgButton(hDlg, IDS_UDP, 1); break; default: break; } return; } void CheckThisProgBoxOn(HWND hDlg, int ButtonID) { switch (ButtonID) { case IDS_CLIENT: /* Shout */ CheckDlgButton(hDlg, IDS_CLIENT, 1); CheckDlgButton(hDlg, IDS_SERVER, 0); break; case IDS_SERVER: /* Listen */ CheckDlgButton(hDlg, IDS_CLIENT, 0); CheckDlgButton(hDlg, IDS_SERVER, 1); break; default: break; } return; } /* 以下就是我们如何处理“模拟阻塞”-本函数检查消息队列,如果发现需要处理的消息,就返回一个正的值。*/ 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; } char * _calloc (nelem, elsize) unsigned nelem, elsize; { HANDLE hMem; PSTR ptr; unsigned size = nelem * elsize; if ((hMem = LocalAlloc(LPTR, size)) == NULL) return (char *) 0; if ((ptr = LocalLock(hMem)) == NULL) { LocalFree(hMem); return (char *) 0; } return (char *) ptr; } void _free (void *cP) { (void) LocalFree(LocalHandle((WORD) cP)); } void ClearBoxes(HWND hOurDlg) { wsprintf(prbuf," \n"); SetDlgItemText(hOurDlg, IDD_WRITE, (LPSTR) prbuf); SetDlgItemText(hOurDlg, IDD_SENT, (LPSTR) prbuf); SetDlgItemText(hOurDlg, IDD_TIME, (LPSTR) prbuf); SetDlgItemText(hOurDlg, IDD_WRITES,(LPSTR) prbuf); SetDlgItemText(hOurDlg, IDD_BYTES, (LPSTR) prbuf); SetDlgItemText(hOurDlg, IDD_BITS, (LPSTR) prbuf); return; } /* * wshout_err()函数 * 描述: * * 通过错误代码获取相应的错误描述文本,与用户提供的错误前缀合 * 并,并显示在对话框中。 */ void wshout_err (HWND hOurDlg, /* 对话框的窗口句柄 */ int wsa_err, /* WinSock错误代码 */ char far *err_prefix) /* 错误前缀字符串 */ { char errbuf[PRBUF_LEN]; /* 错误描述字符串缓冲区 */ /* 获取错误描述字符串 */ WSAsperror(hInst, wsa_err, (LPSTR)errbuf, PRBUF_LEN); /* 合并错误描述字符串与用户错误前缀字符串 */ wsprintf((LPSTR)prbuf, "%s:%s", (LPSTR) err_prefix, (LPSTR)errbuf); /* 在对话框中显示错误文本 */ SetDlgItemText(hOurDlg, IDD_COMMENT, (LPSTR) prbuf); } /* end wshout_err() */ /* eof */ 3.4.3.2 wshout.h清单 /* * 文件名: WSHOUT.H */ #ifndef _WSHOUT_INC_ #define _WSHOUT_INC_ /* Windows 3.0 头文件 */ #include <windows.h> #define _INC_WINDOWS #include <winsock.h> #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* WSHOUT.C 中定义的全局变量 */ extern HANDLE hInst; /* Instance handle */ extern HWND hOurWnd; /* Main Window Handle */ extern int ret; /* work variable */ #define PRBUF_LEN 50 extern char prbuf[PRBUF_LEN]; /* work buffer */ /* 菜单IDs */ #define IDM_START 101 #define IDM_ABOUT 102 #define IDM_STOP 103 #define IDM_EXIT 104 #define IDM_SETTINGS 105 /* 对话框控制IDs */ #define IDD_HNAME 200 #define IDD_CONNECT IDOK #define IDD_CANCEL IDCANCEL #define IDD_WRITES 208 #define IDD_BYTES 210 #define IDD_BITS 212 #define IDD_HELP 214 #define IDD_SENT 230 #define IDD_WRITE 232 #define IDD_TIME 234 #define IDD_COMMENT 236 #define IDD_COHOST 240 /* “Settings”对话框控制IDs */ #define IDS_BUFFLEN 300 #define IDS_PORTNO 301 #define IDS_BLOCK 302 #define IDS_NOBLOCK 304 #define IDS_TCP 306 #define IDS_UDP 308 #define IDS_CLIENT 310 #define IDS_SERVER 312 #define IDS_DEFAULT 314 /* “About”对话框控制IDs */ #define IDA_COPYRIGHT 400 #define IDA_APP_VERSION 402 #define IDA_DLL_VERSION 404 /* 程序控制IDs */ #define WM_SELECT WM_USER+16 /* 全局变量*/ #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 *); #define bcopy(a,b,c) _fmemcpy(b,a,c) char * _calloc (unsigned, unsigned); void _free (void *); #ifdef _cplusplus } #endif /* __cplusplus */ #endif /* ifndef _WSHOUT_INC_ */ /* eof */ 3.4.3.3 wshout.rc清单 /* * 文件名: WSHOUT.RC */ #include <windows.h> #include <winsock.h> #include "wshout.h" MainMenu MENU BEGIN POPUP "&File" BEGIN MENUITEM "&Start", IDM_START MENUITEM "Sto&p", IDM_STOP MENUITEM SEPARATOR MENUITEM "E&xit", IDM_EXIT END POPUP "&Options" BEGIN MENUITEM "&Settings ...", IDM_SETTINGS MENUITEM SEPARATOR MENUITEM "&About Shout...", IDM_ABOUT END END ABOUTBOX DIALOG 22, 17, 144, 102 CAPTION "About Shout for Windows" STYLE DS_MODALFRAME | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU BEGIN CTEXT "Windows Shout", -1, 29, 5, 85, 8 CTEXT "Version", -1, 46, 13, 33, 8, SS_CENTER | WS_GROUP CTEXT "WINSOCK.DLL \n FTP Software, Inc. \nCopyright 1993", IDA_COPYRIGHT, 38, 40, 68, 25, SS_CENTER | WS_GROUP CTEXT "Version", -1, 46, 67, 33, 8, SS_CENTER | WS_GROUP CTEXT "num", IDA_DLL_VERSION, 79, 67, 18, 8, SS_CENTER | WS_GROUP CONTROL "OK", 1, "BUTTON", BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP, 56, 82, 32, 14 ICON "SHOUT", -1, 11, 8, 16, 16 CONTROL "num", IDA_APP_VERSION, "STATIC", SS_LEFT | WS_GROUP, 79, 13, 18, 8 CONTROL "using", -1, "STATIC", SS_CENTER | WS_GROUP, 55, 26, 30, 8 END SettingsDialog DIALOG 9, 16, 172, 117 CAPTION "Settings" STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU BEGIN CONTROL " send/recv \nBuffer &length", -1, "STATIC", SS_LEFT | WS_GROUP, 84, 8, 48, 20 CONTROL "&Port number", -1, "STATIC", SS_LEFT | WS_GROUP, 84, 31, 48, 10 CONTROL "&Blocking", IDS_BLOCK, "BUTTON", BS_AUTOCHECKBOX | WS_TABSTOP, 100, 61, 56, 12 CONTROL "&TCP", IDS_TCP, "BUTTON", BS_AUTOCHECKBOX | WS_TABSTOP, 20, 60, 41, 12 CONTROL "&Client", IDS_CLIENT, "BUTTON", BS_AUTOCHECKBOX | WS_TABSTOP, 19, 15, 35, 12 CONTROL "&Server", IDS_SERVER, "BUTTON", BS_AUTOCHECKBOX | WS_TABSTOP, 19, 26, 35, 12 CONTROL "&UDP", IDS_UDP, "BUTTON", BS_AUTOCHECKBOX | WS_TABSTOP, 20, 72, 41, 12 CONTROL "&Nonblocking", IDS_NOBLOCK, "BUTTON", BS_AUTOCHECKBOX | WS_TABSTOP, 100, 73, 56, 12 CONTROL "O.K.", IDOK, "BUTTON", BS_PUSHBUTTON | WS_TABSTOP, 40, 95, 37, 14 CONTROL "Cancel", IDCANCEL, "BUTTON", BS_PUSHBUTTON | WS_TABSTOP, 90, 95, 37, 14 CONTROL "", IDS_BUFFLEN, "EDIT", ES_CENTER | WS_BORDER | WS_TABSTOP, 130, 11, 36, 12 CONTROL "", IDS_PORTNO, "EDIT", ES_CENTER | WS_BORDER | WS_TABSTOP, 130, 29, 36, 12 CONTROL "Protocol", 237, "button", BS_GROUPBOX, 6, 49, 70, 38 CONTROL "I/O Mode", 239, "button", BS_GROUPBOX, 90, 49, 70, 38 CONTROL "Program Mode", 241, "button", BS_GROUPBOX, 6, 7, 70, 34 END MainDialog DIALOG 17, 32, 163, 135 CAPTION "Windows Shout" MENU MainMenu STYLE DS_ABSALIGN | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX BEGIN CONTROL "", IDD_HNAME, "EDIT", ES_CENTER | WS_BORDER | WS_GROUP | WS_TABSTOP, 62, 9, 93, 12 CONTROL "", IDD_WRITE, "STATIC", SS_CENTER | SS_NOPREFIX | WS_BORDER, 7, 95, 45, 11 CONTROL "", IDD_SENT, "STATIC", SS_CENTER | WS_BORDER, 59, 95, 45, 11 CONTROL "", IDD_TIME, "STATIC", SS_CENTER | WS_BORDER, 111, 95, 45, 11 CONTROL "", IDD_WRITES, "STATIC", SS_CENTER | WS_BORDER, 7, 120, 45, 11 CONTROL "", IDD_BYTES, "STATIC", SS_CENTER | WS_BORDER, 59, 120, 45, 11 CONTROL "", IDD_BITS, "STATIC", SS_CENTER | WS_BORDER, 111, 120, 45, 11 CONTROL "writes[reads]", 105, "STATIC", SS_CENTER | WS_GROUP, 3, 85, 52, 9 CONTROL "writes[reads]/s", 105, "STATIC", SS_CENTER | WS_GROUP, 3, 111, 55, 9 CONTROL "bytes", 105, "STATIC", SS_CENTER | WS_GROUP, 61, 85, 42, 9 CONTROL "bytes/sec", 105, "STATIC", SS_CENTER | WS_GROUP, 61, 111, 42, 9 CONTROL "time (sec)", 105, "STATIC", SS_CENTER | WS_GROUP, 111, 85, 45, 9 CONTROL "bits/sec", 105, "STATIC", SS_CENTER | WS_GROUP, 113, 111, 42, 9 CONTROL "Host", IDD_COHOST, "STATIC", SS_LEFT, 7, 10, 52, 10 CONTROL "", IDD_COMMENT, "STATIC", SS_CENTER | WS_BORDER | WS_GROUP, 9, 68, 146, 11 CONTROL "&Start", IDOK, "BUTTON", BS_PUSHBUTTON | WS_TABSTOP, 6, 32, 32, 20 CONTROL "Sto&p", IDCANCEL, "BUTTON", BS_PUSHBUTTON | WS_TABSTOP, 65, 32, 32, 20 CONTROL "E&xit", IDM_EXIT, "BUTTON", BS_PUSHBUTTON | WS_TABSTOP, 125, 32, 32, 20 CONTROL "", -1, "static", SS_BLACKFRAME, 0, 60, 163, 1 END SHOUT ICON wshout.ico /* * 错误描述字符串表 * 用于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 /* eof */ 3.4.3.4 ushout.c清单 /* * 文件名: USHOUT.C */ #include "wshout.h" /* MSC Include files: */ #include <stdio.h> #include <io.h> #include <string.h> #include <stdlib.h> #include <time.h> /* 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; struct sockaddr_in dest; /* Destination machine address structure */ /* 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: */ for (counter = 0; counter < BUF_SIZE; counter++) DataBuffer[counter] = counter; /* 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); wsprintf((LPSTR)prbuf,"%ld\n",bytes_sent); SetDlgItemText(hOurDlg, IDD_SENT, (LPSTR) prbuf); wsprintf((LPSTR)prbuf,"%ld\n",total_time); SetDlgItemText(hOurDlg, IDD_TIME, (LPSTR) prbuf); ltemp = write_count/total_time; wsprintf((LPSTR)prbuf,"%ld\n", ltemp); SetDlgItemText(hOurDlg, IDD_WRITES,(LPSTR) prbuf); ltemp = bytes_sent/total_time; wsprintf((LPSTR)prbuf,"%ld\n", ltemp); SetDlgItemText(hOurDlg, IDD_BYTES, (LPSTR) prbuf); ltemp = 8 * (bytes_sent/total_time); wsprintf((LPSTR)prbuf,"%ld\n", ltemp); SetDlgItemText(hOurDlg, IDD_BITS, (LPSTR) prbuf); /* 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) */ /* All done */ return bytes_sent; } /* eof */ 3.4.3.5 ulisten.c清单 /* * 文件名: ULISTEN.C */ #include "wshout.h" /* MSC Include files: */ #include <stdio.h> #include <io.h> #include <string.h> #include <stdlib.h> #include <time.h> /* 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); wsprintf((LPSTR)prbuf,"%ld\n",bytes_read); SetDlgItemText(hOurDlg, IDD_SENT, (LPSTR) prbuf); time(&last_time); } /* end: while */ total_time = timeout; wsprintf((LPSTR)prbuf,"%ld\n",total_time); SetDlgItemText(hOurDlg, IDD_TIME, (LPSTR) prbuf); ltemp = num_reads/total_time; wsprintf((LPSTR)prbuf,"%ld\n", ltemp); SetDlgItemText(hOurDlg, IDD_WRITES,(LPSTR) prbuf); ltemp = bytes_read/total_time; wsprintf((LPSTR)prbuf,"%ld\n", ltemp); SetDlgItemText(hOurDlg, IDD_BYTES, (LPSTR) prbuf); ltemp = 8 * (bytes_read/total_time); wsprintf((LPSTR)prbuf,"%ld\n", ltemp); SetDlgItemText(hOurDlg, IDD_BITS, (LPSTR) prbuf); if (bytes_read) { SetDlgItemText(hOurDlg, IDD_COMMENT, "...UDP Listen Done\n"); } /* end: if (bytes_read) */ else { wsprintf((LPSTR)prbuf, "Timed out. No data received.\n"); SetDlgItemText(hOurDlg, IDD_COMMENT, prbuf); goto come_here; } /* end: else */ /* send reply to 'client' */ wsprintf((LPSTR)prbuf, "Replied to %s\n", inet_ntoa(local.sin_addr)); SetDlgItemText(hOurDlg, IDD_COMMENT, prbuf); for (i=0; i<10; ++i) { sprintf(SendBuf, "Rec'd %ld bytes.\n", bytes_read); if(len = sendto(hSock, SendBuf, sizeof(SendBuf), 0, (struct sockaddr FAR *)&local,sizeof(local))) { if (len == SOCKET_ERROR) { /* if could not send bec. */ if (h_errno == WSAEWOULDBLOCK) continue; wshout_err (hOurDlg, WSAGetLastError(), "sendto()"); break; } /* end: if (len == -1) */ } /* end: if (len = sendto()) */ } /* end for */ come_here: return (bytes_read); } /* eof */ 3.4.3.6 tshout.c清单 /* * 文件名: TSHOUT.C */ #include "wshout.h" /* MSC Include files: */ #include <stdio.h> #include <io.h> #include <string.h> #include <stdlib.h> #include <time.h> /* 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: */ for (counter = 0; counter < BUF_SIZE; counter++) DataBuffer[counter] = counter; /* 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 */ } tmp = send(hSock, (char FAR*) &DataBuffer, send_len, 0); if (tmp == SOCKET_ERROR) { if (h_errno == WSAEWOULDBLOCK) continue; else { wshout_err (hOurDlg, WSAGetLastError(), "send()"); } /* 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); ltemp = write_count/total_time; wsprintf((LPSTR)prbuf,"%ld\n", ltemp); SetDlgItemText(hOurDlg, IDD_WRITES,(LPSTR) prbuf); ltemp = bytes_sent/total_time; wsprintf((LPSTR)prbuf,"%ld\n", ltemp); SetDlgItemText(hOurDlg, IDD_BYTES, (LPSTR) prbuf); ltemp = 8 * (bytes_sent/total_time); wsprintf((LPSTR)prbuf,"%ld\n", ltemp); SetDlgItemText(hOurDlg, IDD_BITS, (LPSTR) prbuf); } /* end if (total_time) */ /* All done */ SetDlgItemText(hOurDlg, IDD_COMMENT, "...TCP Shout Done"); return bytes_sent; } /* eof */ 3.4.3.7 tlisten.c清单 /* * 文件名:TLISTEN.C */ #include "wshout.h" /* MSC Include files: */ #include <stdio.h> #include <io.h> #include <string.h> #include <stdlib.h> #include <time.h> /* 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 */ if (hAcceptSock == INVALID_SOCKET) { wshout_err (hOurDlg, WSAGetLastError(), "accept()"); return 0; } /* 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; wsprintf((LPSTR)prbuf,"%d\n",num_reads); SetDlgItemText(hOurDlg, IDD_WRITE, (LPSTR) prbuf); wsprintf((LPSTR)prbuf,"%ld\n",bytes_read); SetDlgItemText(hOurDlg, IDD_SENT, (LPSTR) prbuf); 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 */ wsprintf((LPSTR)prbuf,"%ld\n",total_time); SetDlgItemText(hOurDlg, IDD_TIME, (LPSTR) prbuf); ltemp = num_reads/total_time; wsprintf((LPSTR)prbuf,"%ld\n", ltemp); SetDlgItemText(hOurDlg, IDD_WRITES,(LPSTR) prbuf); ltemp = bytes_read/total_time; wsprintf((LPSTR)prbuf,"%ld\n", ltemp); SetDlgItemText(hOurDlg, IDD_BYTES, (LPSTR) prbuf); ltemp = 8 * (bytes_read/total_time); wsprintf((LPSTR)prbuf,"%ld\n", ltemp); SetDlgItemText(hOurDlg, IDD_BITS, (LPSTR) prbuf); if (bytes_read) { SetDlgItemText(hOurDlg, IDD_COMMENT, "...TCP Listen Done\n"); } /* end: if (bytes_read) */ return (bytes_read); } /* eof */ 3.4.3.8 errno.c清单 #include <windows.h> #include <winsock.h> /* * 文件名: ERRNO.C */ /* * 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 */ } /* end WSAsperror() */ /* eof */ 3.4.3.9 resolve.c清单 /* * 文件名: RESOLVE.C */ #include "wshout.h" /* MSC Include files: */ #include <stdio.h> #include <io.h> #include <string.h> #include <stdlib.h> #include <time.h> 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); SetDlgItemText(hOurDlg, IDD_COMMENT,"Resolving hostname..."); /* Resolve the host name */ host_ptr = gethostbyname(lpHostName); if (host_ptr == NULL) { wshout_err (hOurDlg, WSAGetLastError(), "gethostbyname()"); return (SOCKET) -1; } /* Patch host address into struct describing conn: */ bcopy(host_ptr->h_addr,&dest.sin_addr,host_ptr->h_length); /* Allocate a network (socket) descriptor: */ hSock = socket(PF_INET, iSockType, 0); if (hSock == INVALID_SOCKET) { wshout_err (hOurDlg, WSAGetLastError(), "socket()"); return (SOCKET) -1; } /* Start connection process to host described in 'dest' * * struct. */ SetDlgItemText(hOurDlg, IDD_COMMENT, "Connecting ..."); ret=connect(hSock,(struct sockaddr FAR *)&dest,sizeof(dest)); if (ret == SOCKET_ERROR) { wshout_err (hOurDlg, WSAGetLastError(), "connect()"); closesocket(hSock); return (SOCKET) -1; } SetDlgItemText(hOurDlg, IDD_COMMENT, "...Connected"); return hSock; } SOCKET GetSocketAndBind(HWND hOurDlg, int iProto, int iSockPort) { SOCKET hSock; /* Connection socket descriptor */ struct sockaddr_in local; /* Local machine address structure*/ int iSockType; extern int iTCP; extern int iUDP; /* Internet family addressing */ if (iProto == iTCP) { iSockType = SOCK_STREAM; } else { iSockType = SOCK_DGRAM; } memset(&local, '\0', sizeof (local)); local.sin_family = PF_INET; local.sin_port = htons((u_short)iSockPort); /* allocate a socket descriptor */ hSock = socket(PF_INET, iSockType, 0); if (hSock == INVALID_SOCKET) { /* socket() failed */ wshout_err (hOurDlg, WSAGetLastError(), "socket()"); return (SOCKET) -1; } /* bind socket to a local addr */ ret = bind(hSock, (struct sockaddr FAR *) &local, sizeof(local)); if (ret == SOCKET_ERROR){ /* bind() failed */ wshout_err (hOurDlg, WSAGetLastError(), "bind()"); return (SOCKET) -1; } if (iProto == iUDP) return (hSock); /* If iProto == iTCP, then must listen() and accept() also */ ret = listen(hSock, 0); /* listen on the socket */ if (ret == SOCKET_ERROR){ /* listen() failed */ wshout_err (hOurDlg, WSAGetLastError(), "listen()"); return (SOCKET) -1; } return(hSock); } /* eof */ |
地主 发表时间: 04/29 08:38 |
|
20CN网络安全小组版权所有
Copyright © 2000-2010 20CN Security Group. All Rights Reserved.
论坛程序编写:NetDemon
粤ICP备05087286号