??xml version="1.0" encoding="utf-8" standalone="yes"?>精品无码久久久久久尤物,久久天堂电影网,9191精品国产免费久久 http://www.shnenglu.com/amyvmiwei/category/6011.html 战胜自己是战胜一?
zh-cn Wed, 16 Mar 2011 04:37:48 GMT Wed, 16 Mar 2011 04:37:48 GMT 60 [转]Flex Socket ?C++ 通讯 --- 安全沙箱问题解决 http://www.shnenglu.com/amyvmiwei/archive/2011/03/16/141942.html不?/dc:creator>不?/author>Wed, 16 Mar 2011 02:22:00 GMT http://www.shnenglu.com/amyvmiwei/archive/2011/03/16/141942.html http://www.shnenglu.com/amyvmiwei/comments/141942.html http://www.shnenglu.com/amyvmiwei/archive/2011/03/16/141942.html#Feedback 0 http://www.shnenglu.com/amyvmiwei/comments/commentRss/141942.html http://www.shnenglu.com/amyvmiwei/services/trackbacks/141942.html Flex Socket ?C++ 通讯 --- 安全沙箱问题解决
最q一个项目的客户端要Ҏ(gu)FlexQ用Socket与C++通讯旉C安全沙箱问题Q这是我的解x法;
1):{略文g与主套接字在同一端口Q只需调用 Socket.connect() ?XMLSocket.connect() Ҏ(gu)Q?/p>
2):{略文g与主套接字在不同端口Q需使用Ҏ(gu)?#8220;xmlsocket”语法调用 Security.loadPolicyFile() Ҏ(gu)Q如下所C:(x)
Security.loadPolicyFile("xmlsocket://server.com:2525");
先调?Security.loadPolicyFile() Ҏ(gu)Q然后再调用 Socket.connect() ?XMLSocket.connect() Ҏ(gu)?/p>
试代码Q用同一端口
view plaincopy to clipboardprint? #include <winsock2.h> #include <windows.h> #include <iostream> using namespace std; #pragma comment(lib,"ws2_32.lib") void main() { WORD wVersionRequested; WSADATA wsaData; int err; short port=1800;//端口?nbsp; wVersionRequested = MAKEWORD( 1, 1 ); err = WSAStartup( wVersionRequested, &wsaData );//初始化套接字 if ( err != 0 ) { return; } if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) { WSACleanup( ); return; } SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);//创徏套接?nbsp; SOCKET sockConn;//用来和客L(fng)通信的套接字 SOCKADDR_IN addrSrv;//用来和客L(fng)通信的套接字地址 addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY); addrSrv.sin_family=AF_INET; addrSrv.sin_port=htons(port); bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));//l定端口 listen(sockSrv,5);//侦听 printf("Server %d is listening......\n",port); SOCKADDR_IN addrClient; int len=sizeof(SOCKADDR); char buf[4096];//接收的数?nbsp; char rbuf[100]= "<cross-domain-policy> " "<allow-access-from domain=\"*\" to-ports=\"*\"/>" "</cross-domain-policy> ";//套接字策略文?nbsp; while(1) { //接受q接 sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len); printf("Accept connection from %s\n",inet_ntoa(addrClient.sin_addr)); recv: //接收数据 int bytes; if((bytes=recv(sockConn,buf,sizeof(buf),0))==SOCKET_ERROR) { printf("接收数据p|!\n"); exit(-1); } buf[bytes]='\0'; printf("Message from %s: %s\n",inet_ntoa(addrClient.sin_addr),buf); if (0 == strcmp(buf,"<policy-file-request/>")) { //发送数?nbsp; if(send(sockConn,rbuf,strlen(rbuf)+1,0)==SOCKET_ERROR) { printf("发送数据失败!"); exit(-1); } printf("Message to %s: %s\n",inet_ntoa(addrClient.sin_addr),rbuf); } else { //Echo if(send(sockConn,buf,strlen(buf)+1,0)==SOCKET_ERROR) { printf("发送数据失败!"); exit(-1); } printf("Message to %s: %s\n",inet_ntoa(addrClient.sin_addr),buf); goto recv; } //清理套接字占用的资源 closesocket(sockConn); } } #include <winsock2.h> #include <windows.h> #include <iostream> using namespace std; #pragma comment(lib,"ws2_32.lib")
void main() { WORD wVersionRequested; WSADATA wsaData; int err; short port=1800;//端口?br> wVersionRequested = MAKEWORD( 1, 1 ); err = WSAStartup( wVersionRequested, &wsaData );//初始化套接字 if ( err != 0 ) { return; } if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) { WSACleanup( ); return; } SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);//创徏套接?br>SOCKET sockConn;//用来和客L(fng)通信的套接字 SOCKADDR_IN addrSrv;//用来和客L(fng)通信的套接字地址 addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY); addrSrv.sin_family=AF_INET; addrSrv.sin_port=htons(port); bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));//l定端口 listen(sockSrv,5);//侦听 printf("Server %d is listening......\n",port); SOCKADDR_IN addrClient; int len=sizeof(SOCKADDR); char buf[4096];//接收的数?br>char rbuf[100]= "<cross-domain-policy> " "<allow-access-from domain=\"*\" to-ports=\"*\"/>" "</cross-domain-policy> ";//套接字策略文?br> while(1) { //接受q接 sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len); printf("Accept connection from %s\n",inet_ntoa(addrClient.sin_addr)); recv: //接收数据 int bytes; if((bytes=recv(sockConn,buf,sizeof(buf),0))==SOCKET_ERROR) { printf("接收数据p|!\n"); exit(-1); }
buf[bytes]='\0'; printf("Message from %s: %s\n",inet_ntoa(addrClient.sin_addr),buf);
if (0 == strcmp(buf,"<policy-file-request/>")) { //发送数?br> if(send(sockConn,rbuf,strlen(rbuf)+1,0)==SOCKET_ERROR) { printf("发送数据失败!"); exit(-1); } printf("Message to %s: %s\n",inet_ntoa(addrClient.sin_addr),rbuf); } else { //Echo if(send(sockConn,buf,strlen(buf)+1,0)==SOCKET_ERROR) { printf("发送数据失败!"); exit(-1); } printf("Message to %s: %s\n",inet_ntoa(addrClient.sin_addr),buf); goto recv; } //清理套接字占用的资源 closesocket(sockConn); } }
无论是哪U情况,服务器均必须{待客户端的W一ơ传输之后再军_是发送策略文件还是徏立主q接。当 Flash Player h{略文gӞ它始l会(x)在徏立连接后传输以下字符Ԍ(x)
<policy-file-request/> 服务器收到此字符串后Q即?x)传输该{略文g。程序对于策略文件请求和主连接ƈ不会(x)使用同一q接Q因此应在传输策略文件后关闭q接。如果不关闭q接QFlash Player 关闭策略文件连接,之后重新q接以徏立主q接?/p>
附网l资料:(x)
1,首先目标服务器?43端口是否提供安全{略 2,如果1没有到{略Q则actionscript是否使用了Security.loadPolicyFile(xmlsocket://) 手段提供安全{略Q如果还没检到Q则使用W?步检?br>3,目标服务器目标端口是否提供安全{略
本文来自CSDN博客Q{载请标明出处Q?a >http://blog.csdn.net/xuxiangwin/archive/2009/07/07/4324218.aspx
]]> 【{】完成端口的一个简单封装类 http://www.shnenglu.com/amyvmiwei/archive/2008/01/18/41439.html不?/dc:creator>不?/author>Fri, 18 Jan 2008 13:29:00 GMT http://www.shnenglu.com/amyvmiwei/archive/2008/01/18/41439.html http://www.shnenglu.com/amyvmiwei/comments/41439.html http://www.shnenglu.com/amyvmiwei/archive/2008/01/18/41439.html#Feedback 3 http://www.shnenglu.com/amyvmiwei/comments/commentRss/41439.html http://www.shnenglu.com/amyvmiwei/services/trackbacks/41439.html /////////////////////////////////////////////////////////////////////////////////////
// Iocp 头文?/span>
#pragma once
#include <winsock2.h>
#pragma comment ( lib , "ws2_32.lib" )
const int OP_READ = 0;
const int OP_WRITE = 1;
const int OP_ACCEPT = 2;
/*
OVERLAPPEDPLUS l构体设计思\
OVERLAPPED 是一个固定的用于处理|络消息事gq回值的l构体变?/span>
在完成端口和重叠 I/O 模型里用于返回消息事件的l果
因ؓ(f)在处理网l消息的时候,发送的是一个返回值的l构体指针,只要l构?/span>
的前面部分满系l的要求Q在pȝ操作成功的时候也׃(x)把这个结构体指针
发回l用P我们只要在系l定义的l构体后面扩展一些自q东西Q就可以
很轻杄定该消息是谁发q来的?/span>
不过好像完成端口在设计的时候也满了这L(fng)需求,所以在q里我只是放?/span>
一些与pȝq接有关的数据,用户需要存攄数据q里׃在存?/span>
q里存储与系l相关的数据有:(x)
socket
OpCode 本次消息的操作类型(在完成端口的操作里面Q是以消息通知pȝQ?/span>
L?/span>/ 写数据,都是要发q样的消息结构体q去的,所以如果系l要同时
q行d操作的话Q就需要有一个变量来区分操作了)
WSABUF wbuf; // d~冲区结构体变量
DWORD dwBytes, dwFlags; // 一些在d时用到的标志性变?/span>
char buf[4096]; // 自己的缓冲区
上面?/span>4 个变量存攄是一些与消息相关的数据,都是一些操作上用到的,
q些东西都是固定的,具体作用需要参考一下完成端口相兛_数的参数接口
*/
struct OVERLAPPEDPLUS
{
OVERLAPPED ol;
SOCKET s;
int OpCode;
WSABUF wbuf;
DWORD dwBytes, dwFlags;
char buf[4096];
};
class CIOCP
{
protected :
HANDLE g_hwThread; // 工作U程句柄
DWORD m_wthreadID;
HANDLE g_haThread; // q接U程句柄
DWORD m_athreadID;
public :
bool m_workThread;
bool m_acceptThread;
HANDLE m_hIocp; // 完成端口的句?/span>
SOCKET m_sSocket;
public :
CIOCP(void );
~CIOCP(void );
virtual void OnRead(void * p, char *buf, int len){};
virtual void OnAccept(SOCKET socket);
virtual void OnClose(void * p){};
bool SetIoCompletionPort(SOCKET socket, void *p, char *buf = NULL, int len = 0);
// 把一?/span>socket 与一个自定义的结构体兌到完成端口(相当于把 socket 与一个结构体变量q行l定Q,
// q样当发送上?/span>3 U网l事件的时候,该结构体变量?x)再传回l程?/span>
// q样可以区分当前网l事件是那个 socket 发出?/span>
bool Init(void );
bool Listen(int port);
static DWORD __stdcall WorkThread(LPVOID Param);
static DWORD __stdcall AcceptThread(LPVOID Param);
};
class CIOCPClient: public CIOCP
{
protected :
SOCKET m_socket;
public :
bool Connect(char *ip, int port);
void Send(char *buf, int len);
};
//////////////////////////////////////////////////////////////////////////////////////////
// Iocp 实现文g
#include "StdAfx.h"
#include "iocp.h"
static bool bInit = false ;
DWORD __stdcall CIOCP::WorkThread(LPVOID Param)
{
CIOCP * pthis = (CIOCP *)Param;
void * re;
OVERLAPPED * pOverlap;
DWORD berByte;
while (pthis->m_workThread)
{
int ret;
ret = GetQueuedCompletionStatus(pthis->m_hIocp, &berByte, (LPDWORD)&re, (LPOVERLAPPED *)&pOverlap, INFINITE);
if (ret == ERROR_SUCCESS)
{
}
if (berByte == 0)
{
// 客户端断开q接
pthis->OnClose(re);
OVERLAPPEDPLUS *olp = (OVERLAPPEDPLUS *)pOverlap;
closesocket(olp->s);
delete olp; // 释放 ?/span>socket l定的结构体变量
continue ;
}
if (re == NULL) return 0;
OVERLAPPEDPLUS *olp = (OVERLAPPEDPLUS *)pOverlap;
switch (olp->OpCode)
{
case OP_READ:
pthis->OnRead(re, olp->wbuf.buf, berByte); // 调用 OnRead() 通知应用E序Q服务器收到来自客户端的|络数据
WSARecv(olp->s, &olp->wbuf, 1, &olp->dwBytes, &olp->dwFlags, &olp->ol, NULL); // l箋调用一个接收的 I/O 异步h
break ;
default :
break ;
}
}
return 0;
}
DWORD __stdcall CIOCP::AcceptThread(LPVOID Param)
{
CIOCP * pthis = (CIOCP *)Param;
while (pthis->m_acceptThread)
{
SOCKET client;
if ((client= accept(pthis->m_sSocket, NULL, NULL)) == INVALID_SOCKET)
{
// 错误处理
}
pthis->OnAccept(client); // 调用 OnAccept() 通知应用E序有新客户端连?/span>
}
return 1;
}
CIOCP::CIOCP(void )
{
}
CIOCP::~CIOCP(void )
{
}
bool CIOCP::Init(void )
{
if (bInit)
return true ;
WSADATA wsd;
if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
return false ;
bInit = true ;
return true ;
}
bool CIOCP::Listen(int port)
{
if (!bInit)
if (!Init())
return false ;
m_sSocket = socket(AF_INET, SOCK_STREAM, 0);
if (m_sSocket == INVALID_SOCKET)
return false ;
//SOCKADDR_IN addr;
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
//addr.sin_addr.S_un.S_addr = inet_addr(ip);
if (bind(m_sSocket, (struct sockaddr *)&addr, sizeof (addr)) == SOCKET_ERROR)
return false ;
if (listen(m_sSocket, 10) == SOCKET_ERROR)
return false ;
if ((m_hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0)) == NULL) // 创徏完成端口的句?/span>
return false ;
this ->m_acceptThread = true ;
g_haThread = CreateThread(NULL, 0, AcceptThread, (LPVOID)this , 0, &m_athreadID); // 创徏q接U程Q用来接收客L(fng)的连?/span>
this ->m_workThread = true ;
g_hwThread = CreateThread(NULL, 0, WorkThread, (LPVOID)this , 0, &m_wthreadID); // 创徏工作U程Q用来处理完成端口消息的
return true ;
}
bool CIOCP::SetIoCompletionPort(SOCKET socket, void *p, char *buf, int len)
{
if (CreateIoCompletionPort((HANDLE)socket, m_hIocp, (ULONG_PTR)p, 0) == NULL)
return false ;
OVERLAPPEDPLUS *olp = new OVERLAPPEDPLUS;
memset(olp, 0, sizeof (OVERLAPPEDPLUS));
olp->s = socket;
if (buf)
{
// q里可以使用用户自定义的~冲区地址Q如果用户不惌|,也可以采用默认分配的~冲?/span>
olp->wbuf.buf = buf;
olp->wbuf.len = len;
}
else
{
olp->wbuf.buf = olp->buf;
olp->wbuf.len = 4096;
}
olp->OpCode = OP_READ;
int ret = WSARecv(olp->s, &olp->wbuf, 1, &olp->dwBytes, &olp->dwFlags, &olp->ol, NULL);
if (ret == SOCKET_ERROR)
if (WSAGetLastError() != ERROR_IO_PENDING)
return false ;
return true ;
}
void CIOCP::OnAccept(SOCKET socket)
{
this ->SetIoCompletionPort(socket, NULL);
}
//===================================================================================
bool CIOCPClient::Connect(char *ip, int port)
{
// q接服务?/span>
if (!bInit)
if (!Init())
return false ;
// 初始化连?/span>socket
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_socket == SOCKET_ERROR)
{
// printf("cocket Create fail");
return false ;
}
// 填写服务器地址信息
// 端口?/span>1982
// IP 地址?/span>INADDR_ANY Q注意?/span>htonl ?/span>IP 地址转换为网l格?/span>ServerAddr.sin_family = AF_INET;
sockaddr_in ClientAddr;
ClientAddr.sin_family = AF_INET;
ClientAddr.sin_port = htons(port);
ClientAddr.sin_addr.s_addr = inet_addr(ip);
// l定监听端口
bind(m_socket, (SOCKADDR *)&ClientAddr, sizeof (ClientAddr));
if (connect(m_socket, (SOCKADDR *)&ClientAddr, sizeof (ClientAddr)) == SOCKET_ERROR)
{
return false ;
}
if ((m_hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0)) == NULL) // 创徏完成端口的句?/span>
return false ;
this ->m_workThread = true ;
g_hwThread = CreateThread(NULL, 0, WorkThread, (LPVOID)this , 0, &m_wthreadID); // 创徏工作U程Q用来处理完成端口消息的
this ->SetIoCompletionPort(m_socket, &m_socket); // 讄完成端口监听?/span>socket
return true ;
}
void CIOCPClient::Send(char *buf, int len)
{
send(m_socket, buf, len, 0);
}
///////////////////////////////////////////////////////////////////////////////////
// IOCPclient 应用代码
#include "stdafx.h"
#include "IOCP.h"
#include "TClientSocket.h"
class Iocp :public CIOCPClient
{
void OnRead(void * p, char *buf, int len)
{
printf(buf);
Sleep(1000);
this ->Send(buf, len);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Iocp iocp;
iocp.Init();
iocp.Connect("127.0.0.1", 4311);
iocp.Send("test\0", 5);
gets(new char [1000]);
return 0;
}
]]>【{】完成端口与高性能服务器程序开? http://www.shnenglu.com/amyvmiwei/archive/2008/01/18/41438.html不?/dc:creator>不?/author>Fri, 18 Jan 2008 13:27:00 GMT http://www.shnenglu.com/amyvmiwei/archive/2008/01/18/41438.html http://www.shnenglu.com/amyvmiwei/comments/41438.html http://www.shnenglu.com/amyvmiwei/archive/2008/01/18/41438.html#Feedback 0 http://www.shnenglu.com/amyvmiwei/comments/commentRss/41438.html http://www.shnenglu.com/amyvmiwei/services/trackbacks/41438.html 早在两年前我已l能很熟l的q用完成端口q种技术了,只是一直没有机?x)将它用在什么项目中,q段旉见到q种技术被q分炒作,q分的神U化,想写一解释它如何工作的文?惛_诉大家它没有传说中的那么高深难懂!有什么错误的地方q请高h指正.转蝲h明出处及(qing)作?谢谢! 以一个文件传输服务端Z,在我的机器上它只起两个线E就可以为很多个个客L(fng)同时提供文g下蝲服务,E序的性能?x)随机器内CPU个数的增加而线性增?我尽可能做到使它清晰易懂,虽然E序很小却用CNT 5的一些新Ҏ(gu)?重叠IO,完成端口以及(qing)U程?Zq种模型的服务端E序应该是NTpȝ上性能最好的? 首先.做ؓ(f)完成端口的基,我们应该理解重叠IO,q需要你已经理解了内核对象及(qing)操作pȝ的一些概忉|?什么是信号/非信h?什么是{待函数,什么是成功{待的副作用,什么是U程挂v{?如果q些概o(h)q没有理?你应该先看一下Windows 核心~程中的相关内容.如果已经理解q些,那么重叠IO对你来说q不? 你可以这栯为重叠IO,现在你已l进入一个服务器/客户机环?请不要淆概?q里的服务器是指操作pȝ,而客h是指你的E序(它进行IO操作),是当你进行IO操作(send,recv,writefile,readfile....)时你发送一个IOhl服务器(操作pȝ),由服务器来完成你需要的操作,然后你什么事都没有了,当服务器完成IOh时它?x)通知?当然在这期间你可以做M?一个常用的技巧是在发送重叠IOh?E序在一个@环中一边调用PeekMessage,TranslateMessage和DispatchMessage更新界面,同时调用GetOverlappedResult{待服务器完成IO操作,更高效一点的做法是用IO完成例程来处理服务器(操作pȝ)q回的结?但ƈ不是每个支持重叠IO操作的函数都支持完成例程如TransmitFile函数. ?.一ơ重叠写操作q程(GetOverlappedResultҎ(gu)): 1.填写一个OVERLAPPEDl构 2.q行一ơ写操作,q指定重叠操作参?上面的OVERLAPPEDl构变量的指? 3.做其它事(如更新界? 4.GetOverlappedResult取操作结?br>5.如果IOh没有完成,q且没有出错则回到期Q?br>6.处理IO操作l果 ?.一ơ重叠写操作q程(完成例程Ҏ(gu)): 1.填写一个OVERLAPPEDl构 2.q行一ơ写操作,q指定重叠操作参?上面的OVERLAPPEDl构变量的指?,q指定完成例E?br>3.做其它事(如更新界? 4.当完成例E被调用说明IO操作已经完成或出?现在可以Ҏ(gu)作结果进行处理了 如果你已l理解上面的概念,已l很接近IO完成端口?当然q只是很常规的重叠操作它已经非常高效,但如果再l合多线E对一个File或是Socketq行重叠IO操作׃(x)非常复杂,通常E序员很难把握这U复杂度.完成端口可以说就是ؓ(f)了充分发挥多U程和重叠IO操作相结合的性能而设计的.很多人都说它复杂,其实如果你自己实C个多U程的对一个File或是Socketq行重叠IO操作的程?注意是多个线E对一个HANDLE或SOCKETq行重叠IO操作,而不是启一个线E对一个HANDLEq行重叠IO操作)׃(x)发现完成端口实际上简化了多线E里使用重叠IO的复杂度,q且性能更高,性能高在?下面q行说明. 我们可能写过q样的服务端E序: ?.ȝ? 1.监听一个端?br>2.{待q接 3.当有q接来时 4.启一个线E对q个客户端进行处?br>5.回到2 服务U程: 1.dL(fng)h 2.如果客户端不再有h,执行6 3.处理h 4.q回操作l果 5.回到1 6.退出线E?br> q是一U最单的|络服务器模?我们把它优化一?br> ?.ȝ? 1.开一个线E池,里面有机器能承受的最大线E数个线E?U程都处于挂?suspend)状?br>1.监听一个端?br>2.{待q接 3.当有q接来时 4.从线E池里Resume一个线E对q个客户端进行处?br>5.回到2 服务U程与例3模型里的相同,只是当线E处理完客户端所有请求后,不是退是回到U程?再次挂v让出CPU旉,q等待ؓ(f)下一个客h服务.当然在此期间U程?x)因为IO操作(服务U程的第1,5操作,也许q有其它d操作)挂v自己,但不?x)回到线E池,也就是说它一ơ只能ؓ(f)一个客L(fng)服务. q可能是你能惛_的最高效的服务端模型了吧!它与W一个服务端模型相比了很多个用h到内核态的CONTEXT Switch,反映也更加快?也许你可能觉得这很微不?q说明你~少对大规模高性能服务器程?比如|游服务?的认?如果你的服务端程序要对几千万个客L(fng)q行服务?q也是微软Windows NT开发组在NT 5以上的系l中dU程池的原因. 思考一下什么样的模型可以让一个线Eؓ(f)多个客户端服务呢!那就要蟩出每来一个连接启U程为其服务的固定思维模式,我们把线E服务的最单元分割ؓ(f)单独的读或写操作(注意是读或写不是d?,而不是一个客L(fng)从连接到断开期间的所有读写操?每个U程都用重叠IOq行d操作,投递了dh后线E回到线E池,{待为其它客h服务,当操作完成或出错时再回来处理操作l果,然后再回到线E池. 看看q样的服务器模型: ?.ȝ? 1.开一个线E池,里面有机器内CPU个数两倍的U程,U程都处于挂?suspend)状?它们在都{处理一ơ重叠IO操作的完成结?br>1.监听一个端?br>2.{待q接 3.当有q接来时 4.投递一个重叠读操作d命o(h) 5.回到2 服务U程: 1.如果d?则处理读取的内容(如HTTP GET命o(h)),否则执行3 2.投递一个重叠写操作(如返回HTTP GET命o(h)需要的|页) 3.如果是一个写操作完成,可以再投递一个重叠读操作,d客户机的下一个请?或者是关闭q接(如HTTP协议里每发完一个网就断开) 4.取得下一个重叠IO操作l果,如果IO操作没有完成或没有IO操作则回到线E池 假设q是一个WEB服务器程?可以看到工作者线E是以读或写为最的工作单元q行?在主E序里面q行了一ơ重叠读操作 当读操作完成时一个线E池中的一个工作者线E被Ȁzd得了操作l果,处理GET或POST命o(h),然后发送一个网内?发送也是一个重叠操?然后处理对其它客h的IO操作l果,如果没有其它的东襉K要处理时回到U程池等?可以看到使用q种模型发送和接收可以是也可以不是一个线E? 当发送操作完成时,U程池中的一个工作者线E池Ȁz?它关闭连?HTTP协议),然后处理其它的IO操作l果,如果没有其它的东襉K要处理时回到U程池等? 看看在这L(fng)模型中一个线E怎么为多个客L(fng)服务,同样是模拟一个WEB服务器例? 假如现在pȝ中有两个U程,ThreadA,ThreadB它们在都{处理一ơ重叠IO操作的完成结?br> 当一个客hClientAq接来时ȝ序投递一个重叠读操作,然后{待下一个客hq接,当读操作完成时ThreadA被激z?它收C个HTTP GET命o(h),然后ThreadA使用重叠写操作发送一个网늻C(j)lientA,然后立即回到U程池等待处理下一个IO操作l果,q时发送操作还没有完成,又有一个客hClientBq接?ȝ序再投递一个重叠读操作,当读操作完成时ThreadA(当然也可能是ThreadB)再次被激z?它重复同h?收到一个GET命o(h),使用重叠写操作发送一个网늻C(j)lientB,q次它没有来得及(qing)回到U程池时,又有一个连接ClientCq入,ȝ序再投递一个重叠读操作,L作完成时ThreadB被激z?因ؓ(f)ThreadAq没有回到线E池)它收C个HTTP GET命o(h),然后ThreadB使用重叠写操作发送一个网늻C(j)lientC,然后ThreadB回到U程?q时ThreadA也回CU程? 可以惌现在有三个挂L(fng)发送操作分别是ThreadA发送给C(j)lientA和ClientB的网?以及(qing)ThreadB发送给C(j)lientC的网?它们由操作系l内核来处理.ThreadA和ThreadB现在已经回到U程?可以l箋为其它Q何客L(fng)服务. 当对ClientA的重叠写操作已经完成,ThreadA(也可以是ThreadB)又被Ȁzd关闭与ClientAq接,但还没有回到U程?与此同时发送给C(j)lientB的重叠写操作也完?ThreadB被激z?因ؓ(f)ThreadAq没有回到线E池)它关闭与ClientB的连?然后回到U程?q时ClientC的写操作也完?ThreadB再次被激z?因ؓ(f)ThreadAq是没有回到U程?,它再关闭与ClientC的连?q时ThreadA回到U程?ThreadB也回到线E池.q时对三个客L(fng)的服务全部完?可以看到在整个服务过E中,"建立q接","L?,"写数??关闭q接"{操作是逻辑上连l而实际上分开? 到现在ؓ(f)止两个线E处理了三次L作和三次写操?在这些读写操作过E中所出现的状态机(state machine)是比较复杂的,我们模拟的是l过我简化过?实际上的状态要比这个还要复杂很?然而这L(fng)服务端模型在客户端请求越多时与前两个模型相比的性能高.而用完成端口我们可以很Ҏ(gu)实现q样的服务器模型. 微Y的IIS WEB服务器就是用这L(fng)服务端模?很多什么阿帕奇服务器比IIS的性能好什么什么的我表C怀?除非阿帕奇服务器可以线E分割成,为更的单元服务,我觉得不太可?q种完成端口模型已经单个读或写操作作ؓ(f)最的服务单元,我觉得在相同机器配置的情况下IIS的性能要远q高于其它WEB服务?q也是从实现机理上来分析?如果出现性能上的差别可能是在不同的操作系l上,也许Linux的内核比Windows的要?有h真的研究q吗?q是大家一起在炒作? 对于状态机概念,在很多方面都用到,TCPIP中有,~译原理中有,OpengGL中有{等,我的L数学不好(我是?x)计专业不学q个),不过q是搞懂了些,我想如果你多׃旉?q是可以搞懂?最后是一个简单的文g传输服务器程序代?只用了两个线E?我的机器里只有一块CPU)可以服务多个客L(fng).我调试时用它同时?个nc客户端提供文件下载服务都没有问题,当然更多也不?x)有问?只是略ؓ(f)使用了一下NT 5的线E池和完成端口技术就可以有这样高的性能,更不用说IIS的性能? 希望大家不要陷在q个E序的框架中,Ctrl+C,Ctrl+V没有什么意?要理解它的实?E序使用Visual C++ 6.0 SP5+2003 Platform SDK~译通过,在Windows XP Professional下调试运行通过.E序q行的最低要求是Windows 2000操作pȝ. /******************************************************************** created: 2005/12/24 created: 24:12:2005 20:25 modified: 2005/12/24 filename: d:\vcwork\iocomp\iocomp.cpp file path: d:\vcwork\iocomp file base: iocomp file ext: cpp author: kruglinski(kruglinski_at_gmail_dot_com) purpose: 利用完成端口技术实现的高性能文g下蝲服务E序 *********************************************************************/ #define _WIN32_WINNT 0x0500 #include <cstdlib> #include <clocale> #include <ctime> #include <iostream>//一使用输入输出程序顿时增?0K #include <vector> #include <algorithm> #include <winsock2.h> #include <mswsock.h> using namespace std; #pragma comment(lib,"ws2_32.lib") #pragma comment(lib,"mswsock.lib") const int MAX_BUFFER_SIZE=1024; const int PRE_SEND_SIZE=1024; const int QUIT_TIME_OUT=3000; const int PRE_DOT_TIMER=QUIT_TIME_OUT/80; typedef enum{IoTransFile,IoSend,IoRecv,IoQuit} IO_TYPE; typedef struct { SOCKET hSocket; SOCKADDR_IN ClientAddr; }PRE_SOCKET_DATA,*PPRE_SOCKET_DATA; typedef struct { OVERLAPPED oa; WSABUF DataBuf; char Buffer[MAX_BUFFER_SIZE]; IO_TYPE IoType; }PRE_IO_DATA,*PPRE_IO_DATA; typedef vector<PPRE_SOCKET_DATA> SocketDataVector; typedef vector<PPRE_IO_DATA> IoDataVector; SocketDataVector gSockDataVec; IoDataVector gIoDataVec; CRITICAL_SECTION csProtection; char* TimeNow(void) { time_t t=time(NULL); tm *localtm=localtime(&t); static char timemsg[512]={0}; strftime(timemsg,512,"%Z: %B %d %X,%Y",localtm); return timemsg; } BOOL TransFile(PPRE_IO_DATA pIoData,PPRE_SOCKET_DATA pSocketData,DWORD dwNameLen) { //q一句是为nc做的,你可以修改它 pIoData->Buffer[dwNameLen-1]='\0'; HANDLE hFile=CreateFile(pIoData->Buffer,GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL); BOOL bRet=FALSE; if(hFile!=INVALID_HANDLE_VALUE) { cout<<"Transmit File "<<pIoData->Buffer<<" to client"<<endl; pIoData->IoType=IoTransFile; memset(&pIoData->oa,0,sizeof(OVERLAPPED)); *reinterpret_cast<HANDLE*>(pIoData->Buffer)=hFile; TransmitFile(pSocketData->hSocket,hFile,GetFileSize(hFile,NULL),PRE_SEND_SIZE,reinterpret_cast<LPOVERLAPPED>(pIoData),NULL,TF_USE_SYSTEM_THREAD); bRet=WSAGetLastError()==WSA_IO_PENDING; } else cout<<"Transmit File "<<"Error:"<<GetLastError()<<endl; return bRet; } DWORD WINAPI ThreadProc(LPVOID IocpHandle) { DWORD dwRecv=0; DWORD dwFlags=0; HANDLE hIocp=reinterpret_cast<HANDLE>(IocpHandle); DWORD dwTransCount=0; PPRE_IO_DATA pPreIoData=NULL; PPRE_SOCKET_DATA pPreHandleData=NULL; while(TRUE) { if(GetQueuedCompletionStatus(hIocp,&dwTransCount, reinterpret_cast<LPDWORD>(&pPreHandleData), reinterpret_cast<LPOVERLAPPED*>(&pPreIoData),INFINITE)) { if(0==dwTransCount&&IoQuit!=pPreIoData->IoType) { cout<<"Client:" <<inet_ntoa(pPreHandleData->ClientAddr.sin_addr) <<":"<<ntohs(pPreHandleData->ClientAddr.sin_port) <<" is closed"<<endl; closesocket(pPreHandleData->hSocket); EnterCriticalSection(&csProtection); IoDataVector::iterator itrIoDelete=find(gIoDataVec.begin(),gIoDataVec.end(),pPreIoData); gIoDataVec.erase(itrIoDelete); SocketDataVector::iterator itrSockDelete=find(gSockDataVec.begin(),gSockDataVec.end(),pPreHandleData); gSockDataVec.erase(itrSockDelete); LeaveCriticalSection(&csProtection); delete *itrIoDelete; delete *itrSockDelete; continue; } switch(pPreIoData->IoType){ case IoTransFile: cout<<"Client:" <<inet_ntoa(pPreHandleData->ClientAddr.sin_addr) <<":"<<ntohs(pPreHandleData->ClientAddr.sin_port) <<" Transmit finished"<<endl; CloseHandle(*reinterpret_cast<HANDLE*>(pPreIoData->Buffer)); goto LRERECV; case IoSend: cout<<"Client:" <<inet_ntoa(pPreHandleData->ClientAddr.sin_addr) <<":"<<ntohs(pPreHandleData->ClientAddr.sin_port) <<" Send finished"<<endl; LRERECV: pPreIoData->IoType=IoRecv; pPreIoData->DataBuf.len=MAX_BUFFER_SIZE; memset(&pPreIoData->oa,0,sizeof(OVERLAPPED)); WSARecv(pPreHandleData->hSocket,&pPreIoData->DataBuf,1, &dwRecv,&dwFlags, reinterpret_cast<LPWSAOVERLAPPED>(pPreIoData),NULL); break; case IoRecv: cout<<"Client:" <<inet_ntoa(pPreHandleData->ClientAddr.sin_addr) <<":"<<ntohs(pPreHandleData->ClientAddr.sin_port) <<" recv finished"<<endl; pPreIoData->IoType=IoSend; if(!TransFile(pPreIoData,pPreHandleData,dwTransCount)) { memset(&pPreIoData->oa,0,sizeof(OVERLAPPED)); strcpy(pPreIoData->DataBuf.buf,"File transmit error!\r\n"); pPreIoData->DataBuf.len=strlen(pPreIoData->DataBuf.buf); WSASend(pPreHandleData->hSocket,&pPreIoData->DataBuf,1, &dwRecv,dwFlags, reinterpret_cast<LPWSAOVERLAPPED>(pPreIoData),NULL); } break; case IoQuit: goto LQUIT; default: ; } } } LQUIT: return 0; } HANDLE hIocp=NULL; SOCKET hListen=NULL; BOOL WINAPI ShutdownHandler(DWORD dwCtrlType) { PRE_SOCKET_DATA PreSockData={0}; PRE_IO_DATA PreIoData={0}; PreIoData.IoType=IoQuit; if(hIocp) { PostQueuedCompletionStatus(hIocp,1, reinterpret_cast<ULONG_PTR>(&PreSockData), reinterpret_cast<LPOVERLAPPED>(&PreIoData)); cout<<"Shutdown at "<<TimeNow()<<endl<<"wait for a moment please"<<endl; //让出CPU旉,让线E退?br> for(int t=0;t<80;t+=1) { Sleep(PRE_DOT_TIMER); cout<<"."; } CloseHandle(hIocp); } int i=0; for(;i<gSockDataVec.size();i++) { PPRE_SOCKET_DATA pSockData=gSockDataVec[i]; closesocket(pSockData->hSocket); delete pSockData; } for(i=0;i<gIoDataVec.size();i++) { PPRE_IO_DATA pIoData=gIoDataVec[i]; delete pIoData; } DeleteCriticalSection(&csProtection); if(hListen) closesocket(hListen); WSACleanup(); exit(0); return TRUE; } LONG WINAPI MyExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo) { ShutdownHandler(0); return EXCEPTION_EXECUTE_HANDLER; } u_short DefPort=8182; int main(int argc,char **argv) { if(argc==2) DefPort=atoi(argv[1]); InitializeCriticalSection(&csProtection); SetUnhandledExceptionFilter(MyExceptionFilter); SetConsoleCtrlHandler(ShutdownHandler,TRUE); hIocp=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0); WSADATA data={0}; WSAStartup(0x0202,&data); hListen=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if(INVALID_SOCKET==hListen) { ShutdownHandler(0); } SOCKADDR_IN addr={0}; addr.sin_family=AF_INET; addr.sin_port=htons(DefPort); if(bind(hListen,reinterpret_cast<PSOCKADDR>(&addr), sizeof(addr))==SOCKET_ERROR) { ShutdownHandler(0); } if(listen(hListen,256)==SOCKET_ERROR) ShutdownHandler(0); SYSTEM_INFO si={0}; GetSystemInfo(&si); si.dwNumberOfProcessors<<=1; for(int i=0;i<si.dwNumberOfProcessors;i++) { QueueUserWorkItem(ThreadProc,hIocp,WT_EXECUTELONGFUNCTION); } cout<<"Startup at "<<TimeNow()<<endl <<"work on port "<<DefPort<<endl <<"press CTRL+C to shutdown"<<endl<<endl<<endl; while(TRUE) { int namelen=sizeof(addr); memset(&addr,0,sizeof(addr)); SOCKET hAccept=accept(hListen,reinterpret_cast<PSOCKADDR>(&addr),&namelen); if(hAccept!=INVALID_SOCKET) { cout<<"accept a client:"<<inet_ntoa(addr.sin_addr)<<":"<<ntohs(addr.sin_port)<<endl; PPRE_SOCKET_DATA pPreHandleData=new PRE_SOCKET_DATA; pPreHandleData->hSocket=hAccept; memcpy(&pPreHandleData->ClientAddr,&addr,sizeof(addr)); CreateIoCompletionPort(reinterpret_cast<HANDLE>(hAccept), hIocp,reinterpret_cast<DWORD>(pPreHandleData),0); PPRE_IO_DATA pPreIoData=new(nothrow) PRE_IO_DATA; if(pPreIoData) { EnterCriticalSection(&csProtection); gSockDataVec.push_back(pPreHandleData); gIoDataVec.push_back(pPreIoData); LeaveCriticalSection(&csProtection); memset(pPreIoData,0,sizeof(PRE_IO_DATA)); pPreIoData->IoType=IoRecv; pPreIoData->DataBuf.len=MAX_BUFFER_SIZE; pPreIoData->DataBuf.buf=pPreIoData->Buffer; DWORD dwRecv=0; DWORD dwFlags=0; WSARecv(hAccept,&pPreIoData->DataBuf,1, &dwRecv,&dwFlags, reinterpret_cast<WSAOVERLAPPED*>(pPreIoData),NULL); } else { delete pPreHandleData; closesocket(hAccept); } } } return 0; } 参考资? 《MSDN 2001?br>《Windows |络~程?br>《Windows 核心~程?br>《TCP/IP详解?/font>
]]> socket~程—技术实? http://www.shnenglu.com/amyvmiwei/archive/2008/01/17/41375.html不?/dc:creator>不?/author>Thu, 17 Jan 2008 14:22:00 GMT http://www.shnenglu.com/amyvmiwei/archive/2008/01/17/41375.html http://www.shnenglu.com/amyvmiwei/comments/41375.html http://www.shnenglu.com/amyvmiwei/archive/2008/01/17/41375.html#Feedback 0 http://www.shnenglu.com/amyvmiwei/comments/commentRss/41375.html http://www.shnenglu.com/amyvmiwei/services/trackbacks/41375.html 什么是socketQsocket是...Q我在这里就不抄书了Q有兴趣的同仁去查查书吧?br>不过q要说一句,socket是不同q程之间的一U通信方式。就象打?sh)话是朋友之间的一U通信方式是一栗个人理解:(x)所?#8220;通信”Q就是相互之间发送数据。有人理解socket是不同计机之间的一U通信?br>式,q是不确切的。两个进E,不管是运行在同一台计机上,q是q行在不同计机上,都可通过 socket技术进行通信?br> socket套接字的使用需要有|卡的支持,所以socket一般都被用来在不同机器之间通信Q而如果在同一台计机上的两个q程q行通信Q通常采用效率更高的共享内存技术来实现?br> 两个q程之间q行通讯Q就需要两个进E同旉在运行了Q废话)Q在具体实现中,两个q程我们通常要区别对待,一个进E专门等待另一个进E给自己发消息,收到消息后进行处理,在把处理l果发送回厅R我们把专门处理消息、提供服务的q程UCؓ(f)服务器端Q把发送消息、请求处理的q程UCؓ(f)客户端。Mq程是客户端发送一个消息给服务器端Q服务器端进E收到消息进行处理,把处理结果发送给客户端。恩Q就是这栗?br> q有一个问题,如果我现在有一个进E要跟另一台计机上的某个q程q行socket通信Q那在我q个q程中如何指定另一个进E呢Q这里还需要说一下另一个概念——端口,如果把操作系l比作一座房子的话,那端口就是房子的H口Q是pȝ外界同系l内部进行通信的通道。在socket实现中,我们不进行另一个进E的指定Q而是指定发送消息或接收消息的端口号。比如说现在q程A要给q程B发消息,我们?x)把消息发送到q程B所q行的计机的端口N上,而进EB此时正在监视端口NQ这栯EBp收到q程A发送来的数据,同样q程B也把消息发送到该端口上Q进EA也能从该端口收到q程B发送来的数据,当然Q这需要客L(fng)和服务器端关于端口号q行一个约定,卛_同操作同一个端口。如果客L(fng)把消息发送到端口N1上,而服务器端监视的是端口N2Q那通信一定不能成功。端口号最大ؓ(f)65535Q不能比q个再大了,但在我们自己的程序中量不要用小?024的端口号Q小?024的端口好很多都被pȝ使用了,比如23被telnet所使用?br> socket的实现是很简单的Q只要按照一定的步骤Q就可马上徏立一个这L(fng)通信通道?br> 下面较详l的介绍几个核心的函敎ͼ(x) SOCKET socket(int af, int type, int protocol); 无论是客L(fng)q是服务器端Q下面这个函数是一定要用到的,也是最先用到的?br>q个函数是要告诉pȝQ给我准备好一个socket通道Q我要和其它q程通信了。函数的q回值很重要Q我们要C来,它表C系lؓ(f)我们准备好的q个socket通道Q在以后的每个socket相关函数中都?x)用刎ͼ如果q个值等于SOCKET_ERRORQ表C函数执行失败了。函数的参数我们分别l:(x)PF_INET、SOCK_STREAM和IPPROTO_TCP?br> int bind(SOCKET s, const sockaddr *addr, int namelen); q个函数只有服务器端E序使用Q作用是与某个socket通道l定。可以用q回值判断该函数执行l果怎么P如果{于SOCKET_ERRORQ那是p|了。第一个参数sQ就是socket()函数的返回|在结构addr中,我们要给定一个端口号Qnamelen{于l构sockaddr的大?br> int listen(SOCKET s, int backlog); q个函数只有服务器端E序使用Q作用是监听该端口。返回gbind函数意义一栗?br> int accept(SOCKET s, sockaddr *addr, int *addrlen); q个函数只有服务器端E序使用Q作用是响应客户端的q接。返回gbind函数意义一栗?br> int connect(SOCKET s, const sockaddr *name, int namelen); q个函数只有客户端程序用,作用是把客户端和某个计算机的某个端口建立q接。返回gbind函数意义一栗第一个参数sQ就是socket()函数的返回|在结构name中,我们要给定一个端口号和目的机器名Qnamelen{于l构sockaddr的大?br> int send(SOCKET s, char *buf, int len, int flags); int recv(SOCKET s, char *buf, int len, int flags); q两个函数就是发送数据和接收数据Q客L(fng)和服务器端程序都能用Q哪个发送哪个接收不用说了吧Q呵c(din)?br>从函数的q回值可以检查函数执行是否成功。参Cbuf是指向发送或接收的数据的指针Qlen是数据长度。flags我们l个0可以(其实是我不知道具体含义)?br> 最后就是关闭socket了,q个很容易忘掉,但这个函数很重要Q一定要用?br>int closesocket(SOCKET s); 好了Q关键函数就q么几个Q下图是q几个函数的执行序Q?br> client?service?br> | | v v socket() socket() | | | v | bind() | | | v | listen() | | | v | accept() 挂vQ直到有客户端来q接 | | v 三段握手q程 | connect() <-------------> | | | v 发送消? v +---> send() ---------------> recv() <-------+ | | . | | | . 处理消息 | | v 响应消息 . | +---- recv() <--------------- send() --------+ | | v | close() ---------------> recv() | v closesocket() 上图我觉得能很好的说明客L(fng)和服务器端的q行轨迹?br> 使用以上几个函数?linux pȝ上就可成功徏立一个socket通信q\Q但如果在windowspȝ上,q要用到另一个函敎ͼ(x) int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData); 在windowspȝ上,首先要执行这个函敎ͼ所以要把这个函数放在socket()函数的前面?br> 我对上面的函数进行了一些封装,省篇q,我去掉所有注释和非重要的函数Q在q里可以看到各个函数的具体用法:(x) ?VC60 环境下要q行下面的函敎ͼ要包含头文g errno.h ?winsock2.hQ还有,在连接的时候要q接上ws2_32.dll文g?br> q是头文件内容:(x) class Socket { public: bool setup(); void close(); bool connect(string host, int port); bool listen(); int accept(); int recv(char *buf, int len); int recv(int new_fd, char *buf, int len); int send(const char *msg, int len); int send(int new_fd, const char *msg, int len); private: int _fd; }; q是实现文g内容Q?br>bool Socket::setup() { WSADATA wsd; _fd = WSAStartup(MAKEWORD(2,2), &wsd); if(_fd) { return false; } _fd = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (_fd == -1) { return false; } return true; } bool Socket::listen() { struct sockaddr_in my_addr; my_addr.sin_family = AF_INET; my_addr.sin_port = htons(52309); my_addr.sin_addr.s_addr = INADDR_ANY; if(::bind(_fd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == SOCKET_ERROR) { return false; } if(::listen(_fd, BACKLOG) == SOCKET_ERROR) { return false; } return true; } int Socket::accept() { int new_fd; struct sockaddr_in their_addr; int sin_size = sizeof(their_addr); printf("accepting... \n"); new_fd = ::accept(_fd, (struct sockaddr *)&their_addr, &sin_size); return new_fd == SOCKET_ERROR ? -1:new_fd; } bool Socket::connect(string host, int port) { struct hostent *_h = gethostbyname(host.c_str()); if (_h == 0) { return false; } struct in_addr *_addr = (struct in_addr *)_h->h_addr; struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_addr = *_addr; sin.sin_port = htons(port); if (::connect(_fd, (sockaddr *)&sin, sizeof(sin)) == SOCKET_ERROR) { return false; } return true; } int Socket::recv(int new_fd, char *buf, int len) { int nb = ::recv(new_fd, buf, len, 0); if (nb == -1) { printf("Error! recv.\n"); } return nb; } int Socket::recv(char *buf, int len) { return recv(_fd, buf, len); } int Socket::send(const char *msg, int len) { return send(_fd, msg, len); } int Socket::send(int new_fd, const char *msg, int len) { int nb = ::send(new_fd, msg, len, 0); if (nb == -1) { printf("Error! send.\n"); } return nb; } void Socket::close() { int trytimes = 0; while(::closesocket(_fd) && trytimes < CLOSE_TRY_TIMES) trytimes++; if(trytimes == 10) { printf("Cannot close socket!\n"); } } 好,socketcL装好了Q下面就是组l了Q服务器端和客户端是不一L(fng)Q下面分别给Z码,到这里已l就很简单了?br> 客户端:(x) int main(int argc, char **argv) { printf("socket of client is run ...\n"); Socket s; if (!s.connect("dezhi", 52309)) return 0; char *msg = "ok, send a message."; for (int i=0; i<10; i++) { s.send(msg, 20); printf("message = %s\n", msg); } s.send("q", 1); s.close(); return 0; } 服务器:(x) int main(int argc, char **argv) { printf("socket of service is run ...\n"); Socket s; s.listen(); int new_fd = s.accept(); char buf[8]; buf[7] = '\0'; while (1) { if (s.recv(new_fd, buf, 5) != -1) { printf("%s\n", buf); if (buf[0] == 'q') break; } } s.close(); } 下面行结果:(x) 客户端:(x) socket of client is run ... Socket: WSAStartup success execute. Socket: socket success execute. Socket: Establish the connection to "127.0.0.1:52309" message = ok, send a message. message = ok, send a message. message = ok, send a message. message = ok, send a message. message = ok, send a message. message = ok, send a message. message = ok, send a message. message = ok, send a message. message = ok, send a message. message = ok, send a message. Socket: Close connection to "127.0.0.1:52309" Press any key to continue 服务器端 socket of service is run ... Socket: WSAStartup success execute. Socket: socket success execute. bind ok! listen ok! accepting... ok, send a message. ok, send a message. ok, send a message. ok, send a message. ok, send a message. ok, send a message. ok, send a message. ok, send a message. ok, send a message. ok, send a message. qk, send a message. Press any key to continue 到q里吧。socket的相兛_容可q不止这些,我在q里只是l大家来个抛砖引玉,xIӞ路还很Oѝ关于详l的实现代码Q去我的《源码》上扑Q不攑֜q里Q是Z让篇q小些?/font>
]]> Winsock工作模型 ( ?) http://www.shnenglu.com/amyvmiwei/archive/2008/01/17/41365.html不?/dc:creator>不?/author>Thu, 17 Jan 2008 13:22:00 GMT http://www.shnenglu.com/amyvmiwei/archive/2008/01/17/41365.html http://www.shnenglu.com/amyvmiwei/comments/41365.html http://www.shnenglu.com/amyvmiwei/archive/2008/01/17/41365.html#Feedback 0 http://www.shnenglu.com/amyvmiwei/comments/commentRss/41365.html http://www.shnenglu.com/amyvmiwei/services/trackbacks/41365.html 首先得弄清楚同步、异步、阻塞、非d的概c(din)?br>同步和异步是针对通讯的工作模式,d和非d是指socket的I/O操作?br>实际上对于socketQ只存在d和非dQ同步与异步是在E序实现上有所不同?br>以阻塞的方式执行recv函数Q在没有收到数据前,此函数是不会(x)q回的,所以这很容易执行函数的U程处于{待I/O上的数据状态,然后被挂赗非d׃一P执行recv时候不有没有数据都立卌回,有数据时q回数据Q没数据时返回错误。非d可以带来E序的高效,也带来了写程序中必须注意的地方,非阻塞情况下Q发送与接收数据时候,要用戯q理自q~冲区,q且要记录发送与接受的位|,因ؓ(f)很可能发送与接受数据的Q务不能一ơ完成,需要多ơ调用send和recv才可以完成?br>本来同步异步是用来表C通讯模式的,通信的同步,主要是指客户端在发送请求后Q必d在服务端有回应后才发送下一个请求。所以这个时候的所有请求将?x)在服务端得到同步。通信的异步,指客L(fng)在发送请求后Q不必等待服务端的回应就可以发送下一个请求,q样对于所有的h动作来说会(x)在服务端得到异步Q这条请求的链\p是一个请求队列,所有的动作在这里不?x)得到同步的。但是个人感觉,在说到socket的同步异步时候,同步跟阻塞概念差不多Q都是有了结果才q回Q异步则是告诉系l我要recv数据Q然后马上返回,{待数据来了后,pȝ跟程序说数据CQ然后程序再recv数据。引用在|上看到的比较好的描q?#8220;d block 是指Q你拨通某人的?sh)话Q但是此Z在,于是你拿着?sh)话{他回来Q其间不能再用电(sh)话。同步大概和d差不多。非d nonblock 是指Q你拨通某人的?sh)话Q但是此Z在,于是你挂断电(sh)话,待会(x)儿再打。至于到时候他回来没有Q只有打了电(sh)话才知道。即所谓的“轮询 / poll”。异步是指,你拨通某人的?sh)话Q但是此Z在,于是你叫接电(sh)话的人告诉那?leave a message)Q回来后l你打电(sh)话(call backQ?#8221;
昄Q异步要高效一些。在Winsock中实现异步的Ҏ(gu)有很多,W(xu)insock工作模型有下面六U?br> 一Qselect模型 二:(x)WSAAsyncSelect模型 三:(x)WSAEventSelect模型 四:(x)Overlapped I/O 事g通知模型 五:(x)Overlapped I/O 完成例程模型 六:(x)IOCP模型 从一到六来高U,来高效,实现来复杂。曾在网上看C些比ȝ来很好的说明q些模型Q在q里引用一下?/p>
老陈有一个在外地工作的女儿,不能l常回来Q老陈和她通过信g联系。他们的信会(x)被邮递员投递到他们的信里?br>一Qselect模型
老陈非常想看到女儿的信。以至于他每?0分钟׃楼检查信,看是否有奛_的信~~~~~ 在这U情况下Q?#8220;下楼查信?#8221;然后回到g耽误了老陈太多的时_(d)以至于老陈无法做其他工作?/p>
二:(x)WSAAsyncSelect模型
后来Q老陈使用了微软公司的新式信箱。这U信非常先q,一旦信里有新的信Ӟ盖茨׃(x)l老陈打电(sh)话:(x)喂,大爷Q你有新的信件了Q从此,老陈再也不必频繁上下楼检查信׃Q牙也不gQ你瞅准了,蓝天......不是Q微软~~~~~~~~
三:(x)WSAEventSelect模型
后来Q微软的信箱非常畅销Q购买微软信qZ百万计数......以至于盖茨每?4时l客h?sh)话Q篏得腰酸背痛,喝蚁力神都不好~~~~~~ 微Y改进了他们的信箱Q在客户的家中添加一个附加装|,q个装置?x)监视客L(fng)信箱Q每当新的信件来_(d)此装|会(x)发出“C件到?#8221;壎ͼ提醒老陈L信。盖茨终于可以睡觉了?/p>
四:(x)Overlapped I/O 事g通知模型
后来Q微软通过调查发现Q老陈不喜Ƣ上下楼收发信gQ因Z下楼其实很浪Ҏ(gu)间。于是微软再ơ改q他们的信箱。新式的信箱采用了更为先q的技术,只要用户告诉微Y自己的家在几楼几P新式信箱?x)把信g直接传送到用户的家中,然后告诉用户Q你的信件已l放C的家中了Q老陈很高_(d)因ؓ(f)他不必再亲自收发信g了!
五:(x)Overlapped I/O 完成例程模型
老陈接收到新的信件后Q一般的E序是:(x)打开信封----掏出信纸----阅读信g----回复信g......Zq一步减ȝ戯担,微Y又开发了一U新的技术:(x)用户只要告诉微Y对信件的操作步骤Q微软信将按照q些步骤d理信Ӟ不再需要用户亲自拆?阅读/回复了!老陈l于q上了小资生z!
六:(x)IOCP模型
微Y信箱g很完,老陈也很满意。但是在一些大公司情况却完全不同!q些大公司有C万计的信,每秒钟都有数以百计的信g需要处理,以至于微软信q常因负药转而崩溃!需要重新启动!微Y不得不出杀手锏...... 微Yl每个大公司z了一名名?#8220;Completion Port”的超U机器hQ让q个机器人去处理那些信gQ?/p>
其实Q上面每U模型都有优点,要根据程序需求而适当选择合适的模型Q前面三U模型效率已l比较高Q实现v来难道不大,很多一般的|络E序都采用前三种模型Q只有对|络要求特别高的一些服务器才会(x)考虑用后面的那些模型。MFC中的CAsyncSocketcd是用的WSAAsyncSelect模型Q电(sh)驴中也是用的q种Q不q在L对应socket的时候进行了优化Q查找更快,在GridCast中采用的是WSAEventSelect模型Q等待?/p>
BTWQ上面所说均在Windowsq_下,只用WinSock才有q么多模型,在linux下,好像只有第一Uselect模式Q我对linux下的socket不是很了解,应该也有很多提高效率的地斏V?/p>
]]>
þþƷƷƷ |
˾þô߽Ʒ |
þ99ۺϾƷҳ |
Ʒþþ |
þӰԺһ |
99ȶǾƷþþþþ |
91ƷۺϾþþƷ |
Ļ뾫ƷԴþ |
þþþƷ˵ |
һɫþ88ձȡۺ |
þ99ëƬѹۿ
|
þþþavר |
þþþþþ91Ʒѹۿ |
þþƷ99Ʒ |
ƷëٸAVѾþ |
ҹƷþþþþþС˵ |
þ99Ʒһ |
þó˾ƷƵ |
ɫۺϾþ88ɫۺ |
91þþƷһëƬ |
þþþþúݺݶ |
91þۺ |
þþƷav٤ |
ձƷþþþӰԺձ |
?VþþƷ
|
ŷһþþþþþô |
ľþþþ |
ӰȷŮAV³ɫԴþ |
ƷƬþ |
þþþþþþþþþĻ
|
91ƷѾþþþþþþ |
wwþþþþþþþ |
þþƷƷëƬ |
ҹƷþþĸ
|
þþþþƵ |
þþƷһAV |
þþ뾫ƷպĦ |
þùƷ-Ʒ |
ƷVIDEOSSEXþ÷ |
պۺϾþþ |
þþƷëƬѹۿ |