谁能提供异步SOCKET编程的例子

joinjoy 2000-08-15 12:53:00
要求是使用SOCKET函数编程,程序结构是MFC作的,IO方式是异步的(非阻塞)。
不要光告诉我在codeguru上找,我还没找到呢。
谢了。
...全文
759 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
meifen 2001-07-13
  • 打赏
  • 举报
回复
4
seaboat 2000-09-27
  • 打赏
  • 举报
回复
l634youngpig: GetSocketInformation函数的参数类型是SOCKET还是WPARAM,为什么不一致。
收到FD_READ消息时如何知道消息来源是哪个SOCKET?
l634youngpig 2000-08-19
  • 打赏
  • 举报
回复
// Module Name: asyncselect.cpp
//
// Description:
//
// This sample illustrates how to develop a simple echo server Winsock
// application using the WSAAsyncSelect() I/O model. This sample is
// implemented as a console-style application (to reduce the programming
// complexity of writing a real Windows application) and simply prints
// messages when connections are established and removed from the server.
// The application listens for TCP connections on port 5150 and accepts them
// as they arrive. When this application receives data from a client, it
// simply echos (this is why we call it an echo server) the data back in
// it's original form until the client closes the connection.
//
// Since the WSAAsyncSelect I/O model requires an application to manage
// window messages when network event occur, this application creates
// a window for the I/O model only. The window stays hidden during the
// entire execution of this application.
//
// Compile:
//
// cl -o asyncselect asyncselect.cpp ws2_32.lib user32.lib gdi32.lib
//
// Command Line Options:
//
// asyncselect.exe
//
// Note: There are no command line options for this sample.

#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include <conio.h>

#define PORT 5150
#define DATA_BUFSIZE 8192

typedef struct _SOCKET_INFORMATION {
BOOL RecvPosted;
CHAR Buffer[DATA_BUFSIZE];
WSABUF DataBuf;
SOCKET Socket;
DWORD BytesSEND;
DWORD BytesRECV;
_SOCKET_INFORMATION *Next;
} SOCKET_INFORMATION, * LPSOCKET_INFORMATION;

#define WM_SOCKET (WM_USER + 1)

void CreateSocketInformation(SOCKET s);
LPSOCKET_INFORMATION GetSocketInformation(SOCKET s);
void FreeSocketInformation(SOCKET s);

HWND MakeWorkerWindow(void);
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

LPSOCKET_INFORMATION SocketInfoList;

void main(void)
{
MSG msg;
DWORD Ret;
SOCKET Listen;
SOCKADDR_IN InternetAddr;
HWND Window;
WSADATA wsaData;

if ((Window = MakeWorkerWindow()) == NULL)
return;

// Prepare echo server

if ((Ret = WSAStartup(0x0202, &wsaData)) != 0)
{
printf("WSAStartup failed with error %d\n", Ret);
return;
}

if ((Listen = socket (PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
printf("socket() failed with error %d\n", WSAGetLastError());
return;
}

WSAAsyncSelect(Listen, Window, WM_SOCKET, FD_ACCEPT|FD_CLOSE);

InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(PORT);

if (bind(Listen, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr)) == SOCKET_ERROR)
{
printf("bind() failed with error %d\n", WSAGetLastError());
return;
}

if (listen(Listen, 5))
{
printf("listen() failed with error %d\n", WSAGetLastError());
return;
}

// Translate and dispatch window messages for the application thread

while(Ret = GetMessage(&msg, NULL, 0, 0))
{
if (Ret == -1)
{
printf("GetMessage() failed with error %d\n", GetLastError());
return;
}

TranslateMessage(&msg);
DispatchMessage(&msg);
}
}


LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
SOCKET Accept;
LPSOCKET_INFORMATION SocketInfo;
DWORD RecvBytes, SendBytes;
DWORD Flags;

if (uMsg == WM_SOCKET)
{
if (WSAGETSELECTERROR(lParam))
{
printf("Socket failed with error %d\n", WSAGETSELECTERROR(lParam));
FreeSocketInformation(wParam);
}
else
{
switch(WSAGETSELECTEVENT(lParam))
{
case FD_ACCEPT:

if ((Accept = accept(wParam, NULL, NULL)) == INVALID_SOCKET)
{
printf("accept() failed with error %d\n", WSAGetLastError());
break;
}

// Create a socket information structure to associate with the
// socket for processing I/O.

CreateSocketInformation(Accept);

printf("Socket number %d connected\n", Accept);

WSAAsyncSelect(Accept, hwnd, WM_SOCKET, FD_READ|FD_WRITE|FD_CLOSE);

break;

case FD_READ:

SocketInfo = GetSocketInformation(wParam);

// Read data only if the receive buffer is empty.

if (SocketInfo->BytesRECV != 0)
{
SocketInfo->RecvPosted = TRUE;
return 0;
}
else
{
SocketInfo->DataBuf.buf = SocketInfo->Buffer;
SocketInfo->DataBuf.len = DATA_BUFSIZE;

Flags = 0;
if (WSARecv(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &RecvBytes,
&Flags, NULL, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
printf("WSARecv() failed with error %d\n", WSAGetLastError());
FreeSocketInformation(wParam);
return 0;
}
}
else // No error so update the byte count
{
SocketInfo->BytesRECV = RecvBytes;
}
}

// DO NOT BREAK HERE SINCE WE GOT A SUCCESSFUL RECV. Go ahead
// and begin writing data to the client.

case FD_WRITE:

SocketInfo = GetSocketInformation(wParam);

if (SocketInfo->BytesRECV > SocketInfo->BytesSEND)
{
SocketInfo->DataBuf.buf = SocketInfo->Buffer + SocketInfo->BytesSEND;
SocketInfo->DataBuf.len = SocketInfo->BytesRECV - SocketInfo->BytesSEND;

if (WSASend(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &SendBytes, 0,
NULL, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
printf("WSASend() failed with error %d\n", WSAGetLastError());
FreeSocketInformation(wParam);
return 0;
}
}
else // No error so update the byte count
{
SocketInfo->BytesSEND += SendBytes;
}
}

if (SocketInfo->BytesSEND == SocketInfo->BytesRECV)
{
SocketInfo->BytesSEND = 0;
SocketInfo->BytesRECV = 0;

// If a RECV occurred during our SENDs then we need to post an FD_READ
// notification on the socket.

if (SocketInfo->RecvPosted == TRUE)
{
SocketInfo->RecvPosted = FALSE;
PostMessage(hwnd, WM_SOCKET, wParam, FD_READ);
}
}

break;

case FD_CLOSE:

printf("Closing socket %d\n", wParam);
FreeSocketInformation(wParam);

break;
}
}
return 0;
}

return DefWindowProc(hwnd, uMsg, wParam, lParam);
}


void CreateSocketInformation(SOCKET s)
{
LPSOCKET_INFORMATION SI;

if ((SI = (LPSOCKET_INFORMATION) GlobalAlloc(GPTR,
sizeof(SOCKET_INFORMATION))) == NULL)
{
printf("GlobalAlloc() failed with error %d\n", GetLastError());
return;
}

// Prepare SocketInfo structure for use.

SI->Socket = s;
SI->RecvPosted = FALSE;
SI->BytesSEND = 0;
SI->BytesRECV = 0;

SI->Next = SocketInfoList;

SocketInfoList = SI;
}

LPSOCKET_INFORMATION GetSocketInformation(SOCKET s)
{
SOCKET_INFORMATION *SI = SocketInfoList;

while(SI)
{
if (SI->Socket == s)
return SI;

SI = SI->Next;
}

return NULL;
}

void FreeSocketInformation(SOCKET s)
{
SOCKET_INFORMATION *SI = SocketInfoList;
SOCKET_INFORMATION *PrevSI = NULL;

while(SI)
{
if (SI->Socket == s)
{
if (PrevSI)
PrevSI->Next = SI->Next;
else
SocketInfoList = SI->Next;

closesocket(SI->Socket);
GlobalFree(SI);
return;
}

PrevSI = SI;
SI = SI->Next;
}
}

HWND MakeWorkerWindow(void)
{
WNDCLASS wndclass;
CHAR *ProviderClass = "AsyncSelect";
HWND Window;

wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = (WNDPROC)WindowProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = NULL;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = ProviderClass;

if (RegisterClass(&wndclass) == 0)
{
printf("RegisterClass() failed with error %d\n", GetLastError());
return NULL;
}

// Create a window.

if ((Window = CreateWindow(
ProviderClass,
"",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
NULL,
NULL)) == NULL)
{
printf("CreateWindow() failed with error %d\n", GetLastError());
return NULL;
}

return Window;
}
l634youngpig 2000-08-19
  • 打赏
  • 举报
回复
不好意思这几天有点事,忘了寄现在发
Kevin_qing 2000-08-16
  • 打赏
  • 举报
回复
我要看使用 API的,我不用MFC呀,你们有吗?
kingwill 2000-08-16
  • 打赏
  • 举报
回复
如果你用MFC做SOCKET很简单,CSOCKT类是同步的,也是阻塞的。要做非阻塞的,用 CAsyncSocket类。这是一个非阻塞的异步通讯类,比CSOCKT低级。中间注意的是:因为是非阻塞的,它执行中有很多返回。所以,当返回是SOCKET_ERROR时,要判断ERROR的值。用GetLastError(),如果是WSAEWOULDBLOCK的话,不是有错,而是发生阻塞,你可以及时处理,如重发、忽略。其中CONNECT是需要忽略的。
方法很简单,不要看例子,自己做吧。
服务端:
1:声明两个SOCKET对象:LISTENSOCKET 、WORKSOCKET
2:监听用LISTENSOCKET
3:ACCEPT (WORKSOCKET)
4:RECEIVE、SEND
客户端:
1:声明1个SOCKET
2:CONNECT(HOST)若SOCKET——ERROR此时判断是否WSAEWOULDBLOCK
3:RECEIVE、SEND
要是想在ONSEND、ONRECEIVE、ONACCEPT等触发函数间切换,可用AsyncSelect(FD_READ\FD_WRITE\FD_ACCEPT)等;。
别忘了加分哦!
wedong2000 2000-08-16
  • 打赏
  • 举报
回复
到VCHELP。NET去看看吧,有源程序。
l634youngpig 2000-08-16
  • 打赏
  • 举报
回复
那我就贴出来吧!
l634youngpig 2000-08-16
  • 打赏
  • 举报
回复
异步有很多模式,你到底要哪种!是关于select 的例子吗,或是wsaasyncselect的例子,或是
大规模i/o例子等等,请详细一点?需要哪一种后,我给你email过去
Kevin_qing 2000-08-16
  • 打赏
  • 举报
回复
我也想看看
我都要
qzl@263.net
謝謝
joinjoy 2000-08-16
  • 打赏
  • 举报
回复
我的email:joinjoy@sina.com
joinjoy 2000-08-16
  • 打赏
  • 举报
回复
是wsaasyncselect的例子,vchelp好象没有太合适的。
zzh 2000-08-15
  • 打赏
  • 举报
回复
其实在MSDN中就有,两个聊天程序,客户端和服务端,如果需要别的例程,也可以,我有一个例程。要的话给我EMAIL:zzh1415@21cn.com

16,466

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧