网络安全 频道

一个精巧的应用程序实例-wshout

一个精巧的应用程序实例-wshout

我们通过一个经过精心选择的例子,进一步讨论一下Windows Sockets编程技术。例如如何编制客户机或服务器程序,如何应用TCP有连接服务(流式套接口)或UDP无连接服务(数据报套接口),如何进行阻塞或非阻塞方式的套接口操作等等,这些都是经常碰到的问题。接下来要介绍的wshout程序,可以通过灵活地设置不同选项来达到上述应用情况的任意组合,从而基本覆盖了应用Windows Sockets编程所可能碰到的问题,具有很好的研究参考价值。

由于该程序思路清晰,结构精良,所以我们不打算很详细地剖析每一个语句,而只是简要介绍一下整个程序的逻辑结构,并在源程序中加入适当的注释。我们相信,任何具有基本C语言和Windows编程经验的读者,都能很轻松地读懂绝大部分内容。经过仔细咀嚼和推敲后,更能得到一些编写优质程序的灵感。

该程序在FTP公司的PCTCP支撑环境下调试通过,不过只要读者拥有任何符合Windows Sockets 1.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工具来建立。如果读者使用其他的编译器,可自行作相应的调整,在此不再赘述。

1. wshout.c清单
CODE:
/*

* 文件名: 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);

}
0
相关文章