1.为什么到现在才弄懂这个

不知道这个Socket重叠IO这种模型是不是socket IO完成端口的基础,不过我感觉,学习一下这个再去学习socket IO完成端口是比较有好处的。

这个Scoket重叠IO我以前记得看过好几次,都没看懂。一部分原因是我没能静态心来写代码,还有更重要的原因就是,Socket重叠他们的结构体参数,还有传参数让人很难理解。下面我将对这些数据结构和参数进行一下讲解

2.初识WSARecv 函数

int WSARecv(
SOCKET s,//要接收消息的socket
LPWSABUF lpBuffers, //一个结构体数组。当接收IO操作完毕后接收内容就在这个里面了
DWORD dwBufferCount, //要接多少个WSABUF
LPDWORD lpNumberOfBytesRecvd,//接收了多少个字节
LPDWORD lpFlags,
LPWSAOVERLAPPED lpOverlapped,//Overlapped结构体指针
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine//在本节用不用
);

lpBuffers参数:这是一WSABUF数组,意思是这个函数可以接收不止一个字符缓冲,但是我们一般用一个就够了。 接收多个我还没能测试

dwBufferCount参数:是指上一个参数的数组个数

lpOverlapped参数:这个参数是Overlappad结构体指针,这个指针当IO操作完毕的时候,这里会被系统填充。当IO操作完成时这个结构也可以通过WSAGetOverlappedResult得到

返回值:

0:没有错误发生,IO操作当即完成

SOCKET_ERROR:发生错误

如果是SOCKET_ERROR并且WSAGetLastError() == WSA_IO_PENDING 这时表示操作已经提交。异步操作大部分都是这样的。

3.何时得到收取的消息,然后取出消息

当异常操作完成时,Overlapped的hEvent这个事件会触发。这时Overlapped的InternalHigh表示接受的字节数。Internal表示错误代码。消息的内容即是你当初调用WSARecv时传入的lpBuffers参数。

4.代码组织

以服务端为例

首先传入WSARecv的几个参数必定与一个socket关联。而且这些参数在异步调用完成之后,但是以后还要用(在WaitForMutiObjects时要用到),而且每一个socket得拥有一个不同的Event来标识是哪个客户端来消息了。所以为每一个客户端socket构造一个Overlapped结构。比如我测试的代码中每一个客户端都有这样一个结构体,而且当accept来的时候表示有新的socket连接,就得生成这样一个结构体,当客户端掉线的时候,就得删除这样一个结构体

下面就是这个结构体:

struct CClientInfo
{
public:
CClientInfo()
{
ZeroMemory(&m_ol,sizeof(m_ol));
ZeroMemory(m_szBuf,);
m_ol.hEvent = WSACreateEvent();
}
~CClientInfo()
{
WSACloseEvent(m_ol.hEvent);
}
WSAOVERLAPPED m_ol;
SOCKET sSocket;
CString strIp;
u_short nPort;
CString GetShowText();
char m_szBuf[];
};

下面是两个函数,一个是当客户端连接的时候,一个是当客户端断开的时候

CClientInfo * CServerDlg::OnSocketConnected(SOCKET sClientSocket,sockaddr_in * saClient)
{
u_short uPort = ntohs(((sockaddr_in *)saClient)->sin_port);
CString strIp = CA2T(inet_ntoa(((sockaddr_in *)saClient)->sin_addr));
CClientInfo * pClientInfo = new CClientInfo;
pClientInfo->nPort = uPort;
pClientInfo->strIp = strIp;
pClientInfo->sSocket = sClientSocket;
LockClientArray();
m_ClientArray.Add(pClientInfo);
int nIndexInserted = m_ClientListBox.AddString(pClientInfo->GetShowText());
m_ClientListBox.SetItemData(nIndexInserted,pClientInfo->sSocket);
UnLockClientArray();
return pClientInfo;
} void CServerDlg::OnSocketDisconnect(SOCKET aClientSocket)
{
LockClientArray();
for(int i = ;i<m_ClientArray.GetCount();i++)
{
CClientInfo * pClientInfo = m_ClientArray.GetAt(i);
if(pClientInfo->sSocket == aClientSocket)
{
m_ClientListBox.DeleteString(m_ClientListBox.FindString(,pClientInfo->GetShowText()));
delete pClientInfo;
m_ClientArray.RemoveAt(i);
break;
}
}
UnLockClientArray();
}

5.没有测试的内容和疑问

发送的时候没有用WSASend,以后再学习

6.注意

当使用AcceptEx之后,一般用GetAcceptExSockaddrs这个函数来得到本地或者远程的地址信息。但也可以调用getsockname这个函数,前提是,必须先给接受到socket设置一个SO_UPDATE_ACCEPT_CONTEXT。

7.AcceptEx用法

BOOL AcceptEx(
  __in          SOCKET sListenSocket,
  __in          SOCKET sAcceptSocket,
  __in          PVOID lpOutputBuffer,
  __in          DWORD dwReceiveDataLength,
  __in          DWORD dwLocalAddressLength,
  __in          DWORD dwRemoteAddressLength,
  __out         LPDWORD lpdwBytesReceived,
  __in          LPOVERLAPPED lpOverlapped
);

● sListenSocket 参数指定的是一个监听套接字。
● sAcceptSocket 参数指定的是另一个套接字,负责对进入连接请求的“接受”。
AcceptEx 函数和 accept 函数的区别在于,我们必须提供接受的套接字,而不是让函数自动为我们创建。
正是由于要提供套接字,所以要求我们事先调用 socket 或 WSASocket 函数,创建一个套接字,以便通过 sAcceptSocket 参数,将其传递给 AcceptEx。
● lpOutputBuffer 参数指定的是一个特殊的缓冲区,因为它要负责三种数据的接收:服务器的本地地址,客户机的远程地址,以及在新建连接上发送的第一个数据块。
● dwReceiveDataLength参数以字节为单位,指定了在 lpOutputBuffer 缓冲区中,保留多大的空间,用于数据的接收。
如这个参数设为0,那么在连接的接受过程中,不会再一道接收任何数据。
● dwLocalAddressLength 和 dwRemoteAddressLength 参数也是以字节为单位,指定在 lpOutputBuffer 缓冲区中,保留多大的空间,
在一个套接字被接受的时候,用于本地和远程地址信息的保存。

要注意的是,和当前采用的传送协议允许的最大地址长度比较起来,这里指定的缓冲区大小至少应多出16字节。
举个例子来说:假定正在使用的是 TCP/IP 协议,那么这里的大小应设为“SOCKADDRIN 结构的长度+16字节”。

● lpdwBytesReceived 参数用于返回接收到的实际数据量,以字节为单位。
只有在操作以同步方式完成的前提下,才会设置这个参数。假如 AcceptEx 函数返回 ERROR_IO_PENDING,
那么这个参数永远都不会设置,我们必须利用完成事件通知机制,获知实际读取的字节量。

● lpOverlapped 参数对应的是一个 OVERLAPPED 结构,允许 AcceptEx 以一种异步方式工作。
如我们早先所述,只有在一个重叠 I/O 应用中,该函数才需要使用事件对象通知机制,这是由于此时没有一个完成例程参数可供使用。
也就是说 AcceptEx 函数只能由本节课给大家讲的“事件通知”方式获取异步 I/O 请求的结果,而“完成例程”方法无法被使用。

8.源代码

源码下载 vs2012项目

.h文件

// ServerDlg.h : 头文件
// #pragma once #include "afxwin.h"
#include <Winsock2.h>
#pragma comment(lib,"Ws2_32.lib") #define WM_SOCKET WM_USER+220 enum IO_TYPE
{
IO_RECV,
IO_ACCEPT,
IO_UNKNOW
}; // CServerDlg 对话框
struct CClientInfo
{
public:
CClientInfo()
{
ZeroMemory(&m_ol,sizeof(m_ol));
ZeroMemory(m_szBuf,);
sAcceptSocket = INVALID_SOCKET;
m_ol.hEvent = WSACreateEvent();
m_IO_type = IO_UNKNOW;
}
~CClientInfo()
{
WSACloseEvent(m_ol.hEvent);
}
WSAOVERLAPPED m_ol;
SOCKET sSocket;
SOCKET sAcceptSocket;
CString strIp;
u_short nPort;
CString GetShowText();
char m_szBuf[];
IO_TYPE m_IO_type;
}; class CServerDlg : public CDialogEx
{
// 构造
public:
CServerDlg(CWnd* pParent = NULL); // 标准构造函数
~CServerDlg();
// 对话框数据
enum { IDD = IDD_SERVER_DIALOG }; protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现
protected:
HICON m_hIcon; // 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP() public:
afx_msg void OnBnClickedButton1();
void InitSocket();
SOCKET m_ServerSocket;
CClientInfo * OnSocketConnected(SOCKET sClientSocket,sockaddr_in * saClient);
void OnSocketDisconnect(SOCKET aClientSocket);
CListBox m_ClientListBox;
CArray<CClientInfo *> m_ClientArray;
CListBox m_RecvMsgListBox;
CRITICAL_SECTION m_CS_ClientArray;
void LockClientArray(){EnterCriticalSection(&m_CS_ClientArray);}
void UnLockClientArray(){LeaveCriticalSection(&m_CS_ClientArray);}
afx_msg void OnBnClickedButton3();
void PostRecv(CClientInfo * p);
BOOL PostAccept(SOCKET sListenSocket);
BOOL PostAccept(CClientInfo * p);
void OnError();
};

.cpp文件

// ServerDlg.cpp : 实现文件
// #include "stdafx.h"
#include "Server.h"
#include "ServerDlg.h"
#include "afxdialogex.h"
#include <Mswsock.h> #ifdef _DEBUG
#define new DEBUG_NEW
#endif // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialogEx
{
public:
CAboutDlg(); // 对话框数据
enum { IDD = IDD_ABOUTBOX }; protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现
protected:
DECLARE_MESSAGE_MAP()
}; CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
} void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
} BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP() // CServerDlg 对话框 CServerDlg::CServerDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CServerDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_ServerSocket = INVALID_SOCKET;
InitializeCriticalSection(&m_CS_ClientArray);
}
CServerDlg::~CServerDlg()
{
DeleteCriticalSection(&m_CS_ClientArray);
}
void CServerDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_LIST_CLIENT_LIST, m_ClientListBox);
DDX_Control(pDX, IDC_LIST_RECV, m_RecvMsgListBox);
} BEGIN_MESSAGE_MAP(CServerDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1, &CServerDlg::OnBnClickedButton1)
ON_BN_CLICKED(IDC_BUTTON3, &CServerDlg::OnBnClickedButton3)
END_MESSAGE_MAP() // CServerDlg 消息处理程序 BOOL CServerDlg::OnInitDialog()
{
CDialogEx::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
} // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 InitSocket(); SetDlgItemInt(IDC_EDIT_PORT,); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
} void CServerDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
} // 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。 void CServerDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), ); // 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + ) / ;
int y = (rect.Height() - cyIcon + ) / ; // 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
} //当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CServerDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
} CString CClientInfo::GetShowText()
{
CString strItemText;
strItemText.Format(_T("%s:%d"),strIp,nPort);
return strItemText;
} CClientInfo * CServerDlg::OnSocketConnected(SOCKET sClientSocket,sockaddr_in * saClient)
{
BOOL bDelete = FALSE;
if(saClient == NULL)
{
sockaddr_in * pTempClientAddr = new sockaddr_in;
int nLen = sizeof(sockaddr_in);
if(SOCKET_ERROR == getpeername(sClientSocket,(sockaddr*)pTempClientAddr,&nLen))
{
int nErrorCode = ::WSAGetLastError();
if(SOCKET_ERROR == getpeername(sClientSocket,(sockaddr*)pTempClientAddr,&nLen))
OutputDebugStringA("Failed!\n");
}
saClient = (sockaddr_in*)pTempClientAddr;
bDelete = TRUE;
}
u_short uPort = ntohs(((sockaddr_in *)saClient)->sin_port);
CString strIp = CA2T(inet_ntoa(((sockaddr_in *)saClient)->sin_addr));
CClientInfo * pClientInfo = new CClientInfo;
pClientInfo->nPort = uPort;
pClientInfo->strIp = strIp;
pClientInfo->sSocket = sClientSocket;
pClientInfo->m_IO_type = IO_RECV;
LockClientArray();
m_ClientArray.Add(pClientInfo);
int nIndexInserted = m_ClientListBox.AddString(pClientInfo->GetShowText());
m_ClientListBox.SetItemData(nIndexInserted,pClientInfo->sSocket);
UnLockClientArray();
if(bDelete)
delete saClient;
return pClientInfo;
} void CServerDlg::OnSocketDisconnect(SOCKET aClientSocket)
{
LockClientArray();
for(int i = ;i<m_ClientArray.GetCount();i++)
{
CClientInfo * pClientInfo = m_ClientArray.GetAt(i);
if(pClientInfo->sSocket == aClientSocket)
{
m_ClientListBox.DeleteString(m_ClientListBox.FindString(,pClientInfo->GetShowText()));
delete pClientInfo;
m_ClientArray.RemoveAt(i);
break;
}
}
UnLockClientArray();
} BOOL CServerDlg::PostAccept(SOCKET sListenSocket)
{
// SOCKET sClientSocket = WSASocket(AF_INET,
// SOCK_STREAM,
// IPPROTO_TCP,
// NULL,0,WSA_FLAG_OVERLAPPED);
// char szBuf[256] = {0};
// DWORD dwByteReceived = 0;
// OVERLAPPED ov;
// memset(&ov,0,sizeof(ov));
// AcceptEx(sListenSocket,sClientSocket,szBuf,0,sizeof(sockaddr_in) + 16,sizeof(sockaddr_in) + 16,&dwByteReceived,&ov);
OutputDebugStringA("PostAccept!\n");
CClientInfo * pClientInfo = new CClientInfo;
SOCKET sClientSocket = WSASocket(AF_INET,
SOCK_STREAM,
IPPROTO_TCP,
NULL,,WSA_FLAG_OVERLAPPED);
pClientInfo->sSocket = sListenSocket;
pClientInfo->m_IO_type = IO_ACCEPT;
pClientInfo->sAcceptSocket = sClientSocket;
DWORD dwByteRecieved = ;
int nRet = AcceptEx(pClientInfo->sSocket,pClientInfo->sAcceptSocket,
pClientInfo->m_szBuf,,
sizeof(sockaddr_in) + ,sizeof(sockaddr_in) + ,&dwByteRecieved,
&pClientInfo->m_ol);
if(nRet || ::WSAGetLastError() == ERROR_IO_PENDING)
{
LockClientArray();
m_ClientArray.Add(pClientInfo);
UnLockClientArray();
return TRUE;
}
else
{
AfxMessageBox(_T("出错非常严重!PostAccept"));
return FALSE;
} } BOOL CServerDlg::PostAccept(CClientInfo * pClientInfo)
{
OutputDebugStringA("PostAccept!\n");
SOCKET sClientSocket = WSASocket(AF_INET,
SOCK_STREAM,
IPPROTO_TCP,
NULL,,WSA_FLAG_OVERLAPPED);
pClientInfo->m_IO_type = IO_ACCEPT;
pClientInfo->sAcceptSocket = sClientSocket;
DWORD dwByteRecieved = ;
int nRet = AcceptEx(pClientInfo->sSocket,pClientInfo->sAcceptSocket,
pClientInfo->m_szBuf,,
sizeof(sockaddr_in) + ,sizeof(sockaddr_in) + ,&dwByteRecieved,
&pClientInfo->m_ol);
if(nRet || ::WSAGetLastError() == ERROR_IO_PENDING)
{
return TRUE;
}
else
{
AfxMessageBox(_T("出错非常严重!PostAccept")); delete pClientInfo;
return FALSE;
}
} void CServerDlg::PostRecv(CClientInfo * pClientInfo)
{
OutputDebugStringA("PostRecv!\n");
WSABUF pBuf;
pBuf.buf = pClientInfo->m_szBuf;
pBuf.len = ;
DWORD cbRecv = ;
DWORD dwFlag = ;
int nRet = WSARecv(pClientInfo->sSocket,&pBuf,,&cbRecv,&dwFlag,&pClientInfo->m_ol,NULL);
if(nRet != )
{
int nError = WSAGetLastError();
}
else
{
m_RecvMsgListBox.AddString((LPCTSTR)pBuf.buf);
}
}
UINT AFX_CDECL AcceptThreadProc(LPVOID p)
{
CServerDlg * pThis = (CServerDlg*)p;
while(true)
{
sockaddr_in saClient = {};
int nClientSocketLen = sizeof(saClient);
SOCKET sClientSocket = accept(pThis->m_ServerSocket,(sockaddr *)&saClient,&nClientSocketLen);
CClientInfo * pClientInfo = pThis->OnSocketConnected(sClientSocket,&saClient);
pThis->PostRecv(pClientInfo);
Sleep();
}
return ;
} UINT AFX_CDECL WorkThreadProc(LPVOID p)
{
CServerDlg * pThis = (CServerDlg*)p;
while (true)
{
pThis->LockClientArray();
int nClientCount = pThis->m_ClientArray.GetCount();
WSAEVENT * pEvent = NULL;
if(nClientCount > )
{
pEvent = new WSAEVENT[nClientCount];
for(int i = ;i < nClientCount;i++)
pEvent[i] = pThis->m_ClientArray.GetAt(i)->m_ol.hEvent;
}
pThis->UnLockClientArray();
if(pEvent == NULL)
{
Sleep();
continue;
}
DWORD dwWaitRet = ::WaitForMultipleObjects(nClientCount,pEvent,FALSE,);
if(dwWaitRet == WAIT_FAILED)
{ }
else if(dwWaitRet == WAIT_TIMEOUT)
{ }
else
{
pThis->LockClientArray();
CClientInfo * pClientInfo = pThis->m_ClientArray.GetAt(dwWaitRet - WAIT_OBJECT_0);
WSAResetEvent(pClientInfo->m_ol.hEvent);
char szDbg[] = {};
sprintf_s(szDbg,"OverLapped:Internal:0x%x,InternalHigh:%d,Offset:%d,OffsetHigh:%d\n",
pClientInfo->m_ol.Internal,
pClientInfo->m_ol.InternalHigh,//发了多少字节
pClientInfo->m_ol.Offset,
pClientInfo->m_ol.OffsetHigh);
OutputDebugStringA(szDbg);
switch(pClientInfo->m_IO_type)
{
case IO_RECV:
if(pClientInfo->m_ol.InternalHigh == )
{
//断开连接
pThis->OnSocketDisconnect(pClientInfo->sSocket);
}
else
{
pClientInfo->m_szBuf[pClientInfo->m_ol.InternalHigh] = ;
pThis->m_RecvMsgListBox.AddString((LPCTSTR)pClientInfo->m_szBuf);
pThis->PostRecv(pClientInfo);
}
break;
case IO_ACCEPT:
setsockopt(pClientInfo->sAcceptSocket,
SOL_SOCKET,
SO_UPDATE_ACCEPT_CONTEXT,
(char*)&pClientInfo->sAcceptSocket,
sizeof(pClientInfo->sAcceptSocket));
CClientInfo * pNewClientInfo = pThis->OnSocketConnected(pClientInfo->sAcceptSocket,NULL);
pThis->PostRecv(pNewClientInfo);
pThis->PostAccept(pClientInfo);
break;
} pThis->UnLockClientArray(); } delete [] pEvent;
}
} void CServerDlg::OnBnClickedButton1()
{
//启动服务端
int nPort = GetDlgItemInt(IDC_EDIT_PORT);
// TODO: 在此添加控件通知处理程序代码
m_ServerSocket = WSASocket(AF_INET,
SOCK_STREAM,
IPPROTO_TCP,
NULL,,WSA_FLAG_OVERLAPPED);
if(m_ServerSocket == INVALID_SOCKET)
{
AfxMessageBox(_T("创建套接字失败"));
return ;
}
sockaddr_in saServer;
saServer.sin_family = AF_INET; //地址家族
saServer.sin_port = htons(nPort); //注意转化为网络节序
saServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
if(SOCKET_ERROR == bind(m_ServerSocket,(SOCKADDR *)&saServer,sizeof(saServer)))
{
AfxMessageBox(_T("绑定失败"));
return ;
}
if(SOCKET_ERROR == listen(m_ServerSocket,SOMAXCONN))
{
AfxMessageBox(_T("监听失败啊"));
return ;
} //AfxBeginThread(AcceptThreadProc,this);
PostAccept(m_ServerSocket);
AfxBeginThread(WorkThreadProc,this);
GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);
} void CServerDlg::InitSocket()
{
WSADATA wsaData = {};
if( != WSAStartup(MAKEWORD(,),&wsaData))
{
AfxMessageBox(_T("socket 初始化失败"));
return ;
}
} void CServerDlg::OnBnClickedButton3()
{
// TODO: 在此添加控件通知处理程序代码
if(m_ClientListBox.GetSelCount() <= )
{
AfxMessageBox(_T("请选中右边的客户端进行发送"));
return ;
}
CString strSend;
GetDlgItemText(IDC_EDIT2,strSend);
for(int i = ;i < m_ClientListBox.GetCount();i++)
{
if(m_ClientListBox.GetSel(i) > )
{
SOCKET aClientSocket = m_ClientListBox.GetItemData(i);
if( SOCKET_ERROR == send(aClientSocket,(const char * )strSend.GetBuffer(),strSend.GetLength() * sizeof(TCHAR),))
{
int nError = ::WSAGetLastError();
CString strError;
strError.Format(_T("send 失败%d"),nError);
AfxMessageBox(strError);
}
}
}
}

Socket重叠IO的更多相关文章

  1. winSocket编程(九)重叠IO

    重叠模型的优点 重叠模型的基本原理 关于重叠模型的基础知识 重叠模型的实现步骤 多客户端情况的注意事项 一.重叠模型的优点 1.可以运行在支持Winsock2的所有Windows平台 ,而不像完成端口 ...

  2. 重叠IO

    一. 异步IO        说到重叠模型首先还是提一下异步IO比较好,因为从本质上讲,重叠模型也是一种异步IO模型.       我们知道,相对于计算机执行的其他操作而言,设备IO(文件.管道.套接 ...

  3. 重叠io操作

    第一章 一. 重叠模型的优点 1. 可以运行在支持Winsock2的所有Windows平台 ,而不像完成端口只是支持NT系统. 2. 比起阻塞.select.WSAAsyncSelect以及WSAEv ...

  4. WinSock 重叠IO模型

    title: WinSock 重叠IO模型 tags: [WinSock 模型, 网络编程, 重叠IO模型] date: 2018-06-29 20:26:13 categories: Windows ...

  5. windows网络模型之重叠IO的使用

    大部分内容转载自https://blog.csdn.net/piggyxp/article/details/114883 目录: 1. 重叠模型的优点 2. 重叠模型的基本原理 3. 关于重叠模型的基 ...

  6. 四.Windows I/O模型之重叠IO(overlapped)模型

    1.适用于除Windows CE之外的各种Windows平台.在使用这个模型之前应该确保该系统安装了Winsock2.重叠模型的基本设计原理是使用一个重叠的数据结构,一次投递一个或多个Winsock ...

  7. 重叠IO 模型

    1. 重叠模型的优点 2. 重叠模型的基本原理 3. 关于重叠模型的基础知识 4. 重叠模型的实现步骤 5. 多客户端情况的注意事项 一.重叠模型的优点   1.可以运行在支持Winsock2的所有W ...

  8. socket的IO多路复用

    IO 多路复用 I/O多路复用指:通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作. Linux Linux中的 select,poll, ...

  9. PHP实现网络Socket及IO多路复用

    一直以来,PHP很少用于socket编程,毕竟是一门脚本语言,效率会成为很大的瓶颈,但是不能说PHP就无法用于socket编程,也不能说PHP的socket编程性能就有多么的低,例如知名的一款PHP ...

随机推荐

  1. 夺命雷公狗---DEDECMS----16dedecms取出首页今日更新

    我们这次就要来取出我们的电影和电视剧以及综艺节目: 我们首先在我们受页面的模版文件中获取电影和电视剧的标签: 我们发现这里有一大堆,我只留一个即可: 然后我们到后台更新下首页的模版,看下是否只有一个模 ...

  2. MYSQL日期类型的加减更新使用INTERVAL 1 DAY

    例如:UPDATE teachingplan SET teachPlanBeginTime = teachPlanBeginTime +INTERVAL 1 DAY

  3. 开源软件free download manager在windows defender中报毒

    从官网上下载的fdm lite 3.9.6,从图片中可以看出安装包有数字签名,windows defender报毒,在线杀毒也检出木马,官网的程序更新到了3.9.6版本,在sourceforge上的源 ...

  4. 《zw版·Halcon-delphi系列原创教程》航母舰载机·视觉定位标志的识别代码

    <zw版·Halcon-delphi系列原创教程>航母舰载机·视觉定位标志的识别代码 航母舰载机机身上的黄黑圆圈的标志是什么意思,辐射?核动力?战术核弹? <百度百科>介绍如下 ...

  5. Objective-C代码的文件扩展名与数据类型

    Objective-C数据类型可以分为:基本数据类型.对象类型和id类型. 基本数据类型有:int.float.double和char类型. 对象类型就是类或协议所声明的指针类型,例如:SAutore ...

  6. 使用Application Loader打包上传AppStore流程

    配置完你的证书,Bundle Identifier 和描述文件的配置 然后配置工程打开你项目工程 第一步,这里不能选择模拟器,选择iOS Device 如果不支持横屏,把这2个勾去掉 然后查看版本号和 ...

  7. 分页实体类:PageBean

    package com.eaju.soms.entity.custom; import java.util.List; @SuppressWarnings("rawtypes")p ...

  8. jQuery中attr() 和 prop()【转】

    Version 1.9.0 开始不建议使用 attr() 来对具有 true 和 false 两个属性的属性进行操作. 具有 true 和 false 两个属性的属性,如 checked, selec ...

  9. struts2的两个核心配置文件

    struts2的两个核心配置文件,即:struts.default.xml和struts.properties A,位置:都在struts2-core-version.jar文件中 B,作用,stru ...

  10. setw和setfill控制输出间隔

    在C++中,setw(int n)用来控制输出间隔.例如:cout<<'s'<<setw(8)<<'a'<<endl;则在屏幕显示s a //s与a之间 ...