??xml version="1.0" encoding="utf-8" standalone="yes"?> 另外Q关于cocos2d-x在android上添加第三方库的问题Q?网友塞风朔雪写了一个文档,很有参考h倹{我已把它上传到附g中?/p> 环境winxp + android sdk + ndk r8b+ cygwin 1.7.16-1 + cocos2d-1.0.1-x-0.12.0 1.下蝲android sdk、ndk、cygwin http://dl.google.com/android/android-sdk_r20.0.1-windows.zip http://dl.google.com/android/ndk/android-ndk-r8b-windows.zip 2.android sdk的安装就不多说了Q网上多的是?/p>
ndk解压C含空格的目录下,下文?lt;ndk_dir>来表C压后的ndk根目录?/p>
下蝲好cygwin后,q行setup.exe。需要安装的lg有: autoconf automake binutils gcc-core gcc-g++ gcc4-core gcc4-g++ gdb pcre pcre-devel gawk make 可以在上方search处进行查扑֮装,下文?lt;cyg_dir>表示cygwin的安装目录?/p>
3.cygwin安装好后Q在windows下编?lt;cyg_dir>\home\Administrator\.bash_profile文g 在文件最后添加如下内?/p>
q样Q环境基本上搭建好了,下面需要徏一个hello world工程来验证一下环境是否可用?/p>
1.q行cocos2dx目录下的create-android-project.bat文gQ根据提C入包名(例如Qcn.wey.androidQ、项目名Uͼ例如Qhello2dxQ、所使用的android sdk版本?/p>
2.q行cygwinQ在命oH口中进入刚刚新建的hello2dx目录下的android目录Q运行命?/p>
3.打开eclipseQ导入hello2dx目Q编译ƈq行。即可看到经典的cocos2dx的hello world界面
]]>
~辑cocos2dx目录下的create-android-project.bat文gQ分别修改如下几个变量的?
上面是我的系l中使用的\径,同学们需要根据自q实际情况q行修改?
对工E进行编译,直到最后正常结束?
]]>
]]>
UTF-8~码字符理论上可以最多到6个字节长,然?6位BMPQBasic Multilingual PlaneQ字W最多只用到3字节ѝ下面看一下UTF-8~码表:
U-00000000 - U-0000007F: 0xxxxxxx
U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
xxx 的位|由字符~码数的二进制表C的位填入, 靠右的 x h少的特D意义,只用最短的那个_表达一个字W编码数的多字节丌Ӏ?注意在多字节串中, W一个字节的开?1"的数目就是整个串中字节的数目。而第一行中?开_是ؓ了兼容ASCII~码Qؓ一个字节,W二行就为双字节字符ԌW三行ؓ3字节Q如汉字属于这U,以此cL?个h认ؓQ其实我们可以简单的把前面的1的个数看成字节数)
|魂兵 http://xdotnet.cnblogs.com
Z要将Unicode转换为UTF-8Q当然要知道他们的区别到底在什么地斏V下面来看一下,在Unicode中的~码是怎样转换成UTF-8的,在UTF-8中,如果一个字W的字节于0x80Q?28Q则为ASCII字符Q占一个字节,可以不用转换Q因为UTF-8兼容ASCII~码。假如在Unicode中汉?#8220;?#8221;的编码ؓ“u4F60”Q把它{换ؓ二进制ؓ100111101100000Q然后按照UTF-8的方法进行{换。可以将Unicode二进制从C往高位取出二进制数字,每次?位,如上q的二进制就可以分别取出为如下所C的格式Q前面按格式填补Q不?位用0填补?br />
unicode: 100111101100000 4F60
utf-8: 11100100,10111101,10100000 E4BDA0
从上面就可以很直观的看出Unicode到UTF-8之间的{换,当然知道了UTF-8的格式后Q就可以q行逆运,是按照格式把它在二q制中的相应位置上取出,然后在{换就是所得到的Unicode字符了(q个q算可以通过“位移”来完成)?br /> |魂兵 http://xdotnet.cnblogs.com
如上q的“?#8221;的{换,׃其值大?x800于0x10000Q因此可以判断ؓ三字节存储,则最高位需要向右移“12”位再Ҏ三字节格式的最高位?1100000Q?xE0Q求或(|Q就可以得到最高位的g。同理第二位则是右移“6”位,则还剩下最高位和第二位的二q制|可以通过?11111Q?x3FQ求按位于(&Q操作,再和11000000Q?x80Q求或(|Q。第三位׃用移位了Q只要直接取最后六位(?11111Qox3FQ取&Q,在与11000000(0x80)求或Q|Q。OK了,转换成功Q在VC++中的代码如下所C(Unicode到UTF-8的{换)?br />
1 const wchar_t pUnicode = L"?;
2 char utf8[3+1];
3 memset(utf8,0,4);
4 utf8[0] = 0xE0|(pUnicode>>12);
5 utf8[1] = 0x80|((pUnicode>>6)&0x3F);
6 utf8[2] = 0x80|(pUnicode&0x3F);
7 utf8[3] = "\0";
8 //char[4]是UTF-8的字W?#8220;?#8221;了?
当然在UTF-8到Unicode的{换也是通过UM{来完成的,是把UTF-8那些格式相应的位|的二进制数l揪出来。在上述例子?#8220;?#8221;Z个字节,因此要每个字节进行处理,有高位到低位q行处理。在UTF-8?#8220;?#8221;?1100100,10111101,10100000。从高位起即W一个字?1100100是把其中的"0100"l取出来Q这个很单只要和11111Q?x1FQ取与(&Q,׃字节可以得知最C肯定位于12位之前,因ؓ每次取六位。所以还要将得到的结果左U?2位,最高位也就q样完成?100,000000,000000。而第二位则是要把“111101”l取出来Q则只需第二字?0111101?11111(0x3F)取与Q?amp;Q。在所得到的结果左U?位与最高字节所得的l果取或Q|Q,W二位就q样完成了,得到的结果ؓ0100,111101,000000。以此类推最后一位直接与111111Q?x3FQ取与(&Q,再与前面所得的l果取或Q|Q即可得到结?100,111101,100000。OKQ{换成功!在VC++中的代码如下所C(UTF-8到Unicode的{换)?br />
1 //UTF-8格式的字W串
2 const char* utf8 = "?;
3 wchar_t unicode;
4 unicode = (utf8[0] & 0x1F) << 12;
5 unicode |= (utf8[1] & 0x3F) << 6;
6 unicode |= (utf8[2] & 0x3F);
7 //unicode is ok!
|魂兵 http://xdotnet.cnblogs.com
当然在编E过E中不可能只转换一个字W,q里需要注意的是字W的长度一定要清楚,不然会带?..以上是我这几天研究的结果,至于Unicode的{换ؓGB2312在MFC中Windows有自带的APIQWideCharToMultiByteQ可以{换。这样也p够将UTF-8格式转换为GB2312了,q里׃再赘qͼ如果大家有更好的Ҏ希望指教?br />
]]>
setsockopt(s,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(BOOL));
2. 如果要已l处于连接状态的soket在调用closesocket后强制关闭,不经?br />TIME_WAIT的过E:
BOOL bDontLinger = FALSE;
setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL));
3.在send(),recv()q程中有时由于网l状늭原因Q发收不能预期进?而设|收发时限:
int nNetTimeout=1000;//1U?br />//发送时?br />setsockopt(socketQSOL_S0CKET,SO_SNDTIMEOQ?char *)&nNetTimeout,sizeof(int));
//接收旉
setsockopt(socketQSOL_S0CKET,SO_RCVTIMEOQ?char *)&nNetTimeout,sizeof(int));
4.在send()的时候,q回的是实际发送出ȝ字节(同步)或发送到socket~冲区的字节
(异步);pȝ默认的状态发送和接收一ơؓ8688字节(Uؓ8.5K)Q在实际的过E中发送数?br />和接收数据量比较大,可以讄socket~冲区,而避免了send(),recv()不断的@环收发:
// 接收~冲?br />int nRecvBuf=32*1024;//讄?2K
setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));
//发送缓冲区
int nSendBuf=32*1024;//讄?2K
setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));
5. 如果在发送数据的Ӟ希望不经历由pȝ~冲区到socket~冲区的拯而媄?br />E序的性能Q?br />int nZero=0;
setsockopt(socketQSOL_S0CKET,SO_SNDBUFQ?char *)&nZero,sizeof(nZero));
6.同上在recv()完成上述功能(默认情况是将socket~冲区的内容拯到系l缓冲区)Q?br />int nZero=0;
setsockopt(socketQSOL_S0CKET,SO_RCVBUFQ?char *)&nZero,sizeof(int));
7.一般在发送UDP数据报的时候,希望该socket发送的数据hq播Ҏ:
BOOL bBroadcast=TRUE;
setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char*)&bBroadcast,sizeof(BOOL));
8.在clientq接服务器过E中Q如果处于非d模式下的socket在connect()的过E中?br />以设|connect()延时,直到accpet()被呼?本函数设|只有在非阻塞的q程中有显著?br />作用Q在d的函数调用中作用不大)
BOOL bConditionalAccept=TRUE;
setsockopt(s,SOL_SOCKET,SO_CONDITIONAL_ACCEPT,(const char*)&bConditionalAccept,sizeof(BOOL));
9.如果在发送数据的q程?send()没有完成Q还有数据没发?而调用了closesocket(),以前我们
一般采取的措施?从容关闭"shutdown(s,SD_BOTH),但是数据是肯定丢׃Q如何设|让E序满具体
应用的要?卌没发完的数据发送出d在关闭socket)Q?br />struct linger {
u_short l_onoff;
u_short l_linger;
};
linger m_sLinger;
m_sLinger.l_onoff=1;//(在closesocket()调用,但是q有数据没发送完毕的时候容讔R留)
// 如果m_sLinger.l_onoff=0;则功能和2.)作用相同;
m_sLinger.l_linger=5;//(容许逗留的时间ؓ5U?
setsockopt(s,SOL_SOCKET,SO_LINGER,(const char*)&m_sLinger,sizeof(linger));
讄套接口的选项?br /> #include <winsock.h>
int PASCAL FAR setsockopt( SOCKET s, int level, int optname,
const char FAR* optval, int optlen);
sQ标识一个套接口的描q字?br /> levelQ选项定义的层ơ;目前仅支持SOL_SOCKET和IPPROTO_TCP层次?br /> optnameQ需讄的选项?br /> optvalQ指针,指向存放选项值的~冲区?br /> optlenQoptval~冲区的长度?br />注释Q?br />setsockopt()函数用于Lcd、Q意状态套接口的设|选项倹{尽在不同协议层上存在选项Q但本函C定义了最高的“套接?#8221;层次上的选项。选项影响套接口的操作Q诸如加急数据是否在普通数据流中接Ӟq播数据是否可以从套接口发送等{?br /> 有两U套接口的选项Q一U是布尔型选项Q允许或止一U特性;另一U是整Ş或结构选项。允怸个布型选项Q则optval指向非零整Ş敎ͼ止一个选项optval指向一个等于零的整形数。对于布型选项Qoptlen应等于sizeof(int)Q对其他选项Qoptval指向包含所需选项的整形数或结构,而optlen则ؓ整Ş数或l构的长度。SO_LINGER选项用于控制下述情况的行动:套接口上有排队的待发送数据,?closesocket()调用已执行。参见closesocket()函数中关于SO_LINGER选项对closesocket()语义的媄响。应用程序通过创徏一个lingerl构来设|相应的操作Ҏ:
struct linger {
int l_onoff;
int l_linger;
};
Z允许SO_LINGERQ应用程序应l_onoff设ؓ非零Q将l_linger设ؓ零或需要的时|以秒为单位)Q然后调用setsockopt()。ؓ了允许SO_DONTLINGERQ亦即禁止SO_LINGERQ,l_onoff应设为零Q然后调用setsockopt()?br /> ~省条g下,一个套接口不能与一个已在用中的本地地址捆绑Q参见bind()Q。但有时会需?#8220;重用”地址。因为每一个连接都由本地地址和远端地址的组合唯一定Q所以只要远端地址不同Q两个套接口与一个地址捆绑q无大碍。ؓ了通知WINDOWS套接口实C要因Z个地址已被一个套接口使用׃让它与另一个套接口捆绑Q应用程序可在bind()调用前先讄SO_REUSEADDR选项。请注意仅在bind()调用时该选项才被解释Q故此无需Q但也无宻I一个不会共用地址的套接口讄该选项Q或者在bind()对这个或其他套接口无影响情况下设|或清除q一选项?br /> 一个应用程序可以通过打开SO_KEEPALIVE选项Q得WINDOWS套接口实现在TCPq接情况下允怋?#8220;保持zd”包。一个WINDOWS套接口实现ƈ不是必需支持“保持zd”Q但是如果支持的话,具体的语义将与实现有养I应遵守RFC1122“InternetL要求Q通讯?#8221;中第 4.2.3.6节的规范。如果有兌接由?#8220;保持zd”而失效,则进行中的Q何对该套接口的调用都以WSAENETRESET错误q回Q后l的M调用以WSAENOTCONN错误q回?br /> TCP_NODELAY选项止Nagle法。Nagle法通过未认的数据存入缓冲区直到蓄一个包一起发送的ҎQ来减少L发送的零碎数据包的数目。但对于某些应用来说Q这U算法将降低pȝ性能。所以TCP_NODELAY可用来将此算法关闭。应用程序编写者只有在切了解它的效果q确实需要的情况下,才设|TCP_NODELAY选项Q因|后对网l性能有明昄负面影响。TCP_NODELAY是唯一使用IPPROTO_TCP层的选项Q其他所有选项都用SOL_SOCKET层?br /> 如果讄了SO_DEBUG选项QWINDOWS套接口供应商被鼓励(但不是必需Q提供输出相应的调试信息。但产生调试信息的机制以及调试信息的形式已超出本规范的讨围?br />setsockopt()支持下列选项。其?#8220;cd”表明optval所指数据的cd?br />选项 cd 意义
SO_BROADCAST BOOL 允许套接口传送广播信息?br />SO_DEBUG BOOL 记录调试信息?br />SO_DONTLINER BOOL 不要因ؓ数据未发送就d关闭操作。设|本选项相当于将SO_LINGER的l_onoff元素|ؓ零?br />SO_DONTROUTE BOOL 止选径Q直接传送?br />SO_KEEPALIVE BOOL 发?#8220;保持zd”包?br />SO_LINGER struct linger FAR* 如关闭时有未发送数据,则逗留?br />SO_OOBINLINE BOOL 在常规数据流中接收带外数据?br />SO_RCVBUF int 为接收确定缓冲区大小?br />SO_REUSEADDR BOOL 允许套接口和一个已在用中的地址捆绑Q参见bind()Q?br />SO_SNDBUF int 指定发送缓冲区大小?br />TCP_NODELAY BOOL 止发送合q的Nagle法?br />setsockopt()不支持的BSD选项有:
选项?nbsp; cd 意义
SO_ACCEPTCONN BOOL 套接口在监听?br />SO_ERROR int 获取错误状态ƈ清除?br />SO_RCVLOWAT int 接收低水印?br />SO_RCVTIMEO int 接收时?br />SO_SNDLOWAT int 发送低U水印?br />SO_SNDTIMEO int 发送超时?br />SO_TYPE int 套接口类型?br />IP_OPTIONS 在IP头中讄选项?br />q回|
若无错误发生Qsetsockopt()q回0。否则的话,q回SOCKET_ERROR错误Q应用程序可通过WSAGetLastError()获取相应错误代码?br />错误代码Q?br /> WSANOTINITIALISEDQ在使用此API之前应首先成功地调用WSAStartup()?br /> WSAENETDOWNQWINDOWS套接口实现检到|络子系l失效?br /> WSAEFAULTQoptval不是q程地址I间中的一个有效部分?br /> WSAEINPROGRESSQ一个阻塞的WINDOWS套接口调用正在运行中?br /> WSAEINVALQlevel值非法,或optval中的信息非法?br /> WSAENETRESETQ当SO_KEEPALIVE讄后连接超时?br /> WSAENOPROTOOPTQ未知或不支持选项。其中,SOCK_STREAMcd的套接口不支持SO_BROADCAST选项QSOCK_DGRAM cd的套接口不支持SO_DONTLINGER 、SO_KEEPALIVE、SO_LINGER和SO_OOBINLINE选项?br /> WSAENOTCONNQ当讄SO_KEEPALIVE后连接被复位?br /> WSAENOTSOCKQ描q字不是一个套接口?img src ="http://www.shnenglu.com/zhengxf/aggbug/160291.html" width = "1" height = "1" />
]]>
|关服务器的功能是将: 游戏服务? 客户端和数据库服务器之间的消息进行{? 所以它负责理客户端的q接和服务端的连? q{发他们之间的消息, 同时他还q接到数据库服务器上,{需要数据读取是Ҏ据库q行操作,q{发给相应的请求? (其实在对数据库的q接q个问题上,有游戏服务器来连接的Q网x务只负责转发和简单的逻辑处理)?br> 我们现在来讨Z|关服务器是怎么实现的:|关服务器要理两个事情Q一个是游戏服务器的q接Q另一个玩家的q接。其实对于网x务器而言Q这两个U类型的q接差别Qƈ不是很大Q可以用一个网路模型来处理收到的消息,q将其{发给相应的接受者?br> 游戏服务器中的地图服务器Q地图服务器相对于网x务器而言Q它更像是一个客LQ它在收到消息的时候处理消息,q将消息l果q回l网养I|关把消息{l相应的q接。只是说因ؓ地图服务器相Ҏ说是处理那些长时间连接,需要不断处理的逻辑的,如用LUdQ状态,补给{,需要实时的消息处理?br> 逻辑服务器的功能是实现如打怪,l队{一些,不经怺互的逻辑的。其实对于一l游戏服务器而言Q大量的聊天信息也是很消耗系l资源的Q有时候要单独建立一个聊天服务器?br> 数据库服务器基本上是存放数据库的Q游戏服务器Q逻辑服务器,在需要是d数据Q进行逻辑处理?br>
]]>
Windows 的IPCQ进E间通信Q机制主要是异步道和命名管道。(至于其他的IPC方式Q例如内存映、邮槽等q里׃介绍了)
道QpipeQ是用于q程间通信的共享内存区域。创建管道的q程UCؓ道服务器,而连接到q个道的进E称为管道客L。一个进E向道写入信息Q而另外一个进E从道d信息?br>异步道是基于字W和半双工的Q即单向Q,一般用于程序输入输出的重定向;命名道则强大地多,它们是面向消息和全双工的Q同时还允许|络通信Q用于创建客L/服务器系l?br>一、异步管?实现比较单,直接通过实例来讲?
实验目标Q当前有sample.cpp, sample.exe, sample.inq三个文Ӟsample.exe为sample.cpp的执行程序,sample.cpp只是一个简单的E序CZQ简单求和)Q如下:
#include <iostream.h>
int main()
{
int a, b ;
while ( cin >> a >> b && ( a || b ) )
cout << a + b << endl ;
return 0;
}
542 657
0 0
要求Ҏsample.exe和它的输入数据,把输出数据重定向到sample.out
程分析Q实际这个实验中包含两个部分Q把输入数据重定向到sample.exe 和把输出数据重定向到sample.out。在命o行下可以很简单的实现q个功能“sample <sample.in >sample.out”Q这个命令也是利用管道特性实现的Q现在我们就Ҏ异步道的实现原理自己来实现q个功能?br>道是基于半双工Q单向)的,q里有两个重定向的过E,昄需要创Z个管道,下面l出程图:
异步道实现的流E图说明Q?br>1Q。父q程是我们需要实现的Q其中需要创建管道AQ管道BQ和子进E,整个实现程分ؓ4个操作?br>2Q。管道AQ输入管?br>3Q。管道BQ输出管?br>4Q。操作AQ把输入文gsample.in的数据写入输入管道(道AQ?br>5Q。操作BQ子q程从输入管道中d数据Q作q程的加工原料。通常Q程序的输入数据由标准的输入讑֤输入Q这里实现输入重定向Q即把输入管道作入设备?br>6Q。操作CQ子q程把加工后的成品(输出数据Q输出到输出道。通常Q程序的输出数据会输出到标准的输备,一般ؓ屏幕Q这里实现输出重定向Q即把输出管道作备?br>7Q。操作DQ把输出道的数据写入输出文?br>需要注意的是,道的本质只是一个共享的内存区域。这个实验中Q管道区域处于父q程的地址I间中,父进E的作用是提供环境和资源Qƈ协调子进E进行加工?br>E序源码Q?br>
#include <windows.h>
#include <iostream.h>
const int BUFSIZE = 4096 ;
HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
hChildStdoutRd,hChildStdoutWr,hChildStdoutRdDup,
hSaveStdin, hSaveStdout;
BOOL CreateChildProcess(LPTSTR);
VOID WriteToPipe(LPTSTR);
VOID ReadFromPipe(LPTSTR);
VOID ErrorExit(LPTSTR);
VOID ErrMsg(LPTSTR, BOOL);
void main( int argc, char *argv[] )
{
// 处理输入参数
if ( argc != 4 )
return ;
// 分别用来保存命o行,输入文g名(CPP/CQ,输出文g名(保存~译信息Q?
LPTSTR lpProgram = new char[ strlen(argv[1]) ] ;
strcpy ( lpProgram, argv[1] ) ;
LPTSTR lpInputFile = new char[ strlen(argv[2]) ];
strcpy ( lpInputFile, argv[2] ) ;
LPTSTR lpOutputFile = new char[ strlen(argv[3]) ] ;
strcpy ( lpOutputFile, argv[3] ) ;
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
/************************************************
* redirecting child process's STDOUT *
************************************************/
hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);
if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
ErrorExit("Stdout pipe creation failed\n");
if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr))
ErrorExit("Redirecting STDOUT failed");
BOOL fSuccess = DuplicateHandle(
GetCurrentProcess(),
hChildStdoutRd,
GetCurrentProcess(),
&hChildStdoutRdDup ,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
if( !fSuccess )
ErrorExit("DuplicateHandle failed");
CloseHandle(hChildStdoutRd);
/************************************************
* redirecting child process's STDIN *
************************************************/
hSaveStdin = GetStdHandle(STD_INPUT_HANDLE);
if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))
ErrorExit("Stdin pipe creation failed\n");
if (! SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd))
ErrorExit("Redirecting Stdin failed");
fSuccess = DuplicateHandle(
GetCurrentProcess(),
hChildStdinWr,
GetCurrentProcess(),
&hChildStdinWrDup,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
if (! fSuccess)
ErrorExit("DuplicateHandle failed");
CloseHandle(hChildStdinWr);
/************************************************
* 创徏子进E(卛_动SAMPLE.EXEQ?nbsp; *
************************************************/
fSuccess = CreateChildProcess( lpProgram );
if ( !fSuccess )
ErrorExit("Create process failed");
// 父进E输入输出流的还原设|?
if (! SetStdHandle(STD_INPUT_HANDLE, hSaveStdin))
ErrorExit("Re-redirecting Stdin failed\n");
if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout))
ErrorExit("Re-redirecting Stdout failed\n");
WriteToPipe( lpInputFile ) ;
ReadFromPipe( lpOutputFile );
delete lpProgram ;
delete lpInputFile ;
delete lpOutputFile ;
}
BOOL CreateChildProcess( LPTSTR lpProgram )
{
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
BOOL bFuncRetn = FALSE;
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
bFuncRetn = CreateProcess ( NULL, lpProgram, NULL, NULL, TRUE, \
0, NULL, NULL, &siStartInfo, &piProcInfo);
if (bFuncRetn == 0)
{
ErrorExit("CreateProcess failed\n");
return 0;
}
else
{
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
return bFuncRetn;
}
}
VOID WriteToPipe( LPTSTR lpInputFile )
{
HANDLE hInputFile = CreateFile(lpInputFile, GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
if (hInputFile == INVALID_HANDLE_VALUE)
return ;
BOOL fSuccess ;
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE] = {0} ;
for (;;)
{
fSuccess = ReadFile( hInputFile, chBuf, BUFSIZE, &dwRead, NULL) ;
if ( !fSuccess || dwRead == 0)
break;
fSuccess = WriteFile( hChildStdinWrDup, chBuf, dwRead, &dwWritten, NULL) ;
if ( !fSuccess )
break;
}
if (! CloseHandle(hChildStdinWrDup))
ErrorExit("Close pipe failed\n");
CloseHandle ( hInputFile ) ;
}
VOID ReadFromPipe( LPTSTR lpOutputFile )
{
HANDLE hOutputFile = CreateFile( lpOutputFile, GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hOutputFile == INVALID_HANDLE_VALUE)
return ;
BOOL fSuccess ;
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE] = { 0 };
if (!CloseHandle(hChildStdoutWr))
ErrorExit("Closing handle failed");
for (;;)
{
fSuccess = ReadFile( hChildStdoutRdDup, chBuf, BUFSIZE, &dwRead, NULL) ;
if( !fSuccess || dwRead == 0)
{
break;
}
fSuccess = WriteFile( hOutputFile, chBuf, dwRead, &dwWritten, NULL) ;
if ( !fSuccess )
break;
}
CloseHandle ( hOutputFile ) ;
}
VOID ErrorExit (LPTSTR lpszMessage)
{
MessageBox( 0, lpszMessage, 0, 0 );
}
隄所在:
实现的过E比较简单,但有一个难炏V原本当服务端用ConnectNamedPipe函数后,如果有客Lq接Q就可以直接q行交互。原来我在实现过E中Q当道I闲Ӟ道的线E函C无限QINFINITEQ阻塞。若现在需要停止服务,必ȝ束所有的U程QTernimateThread可以作ؓ一个结束线E的ҎQ但我基本不用这个函数。一旦用这个函C后,目标U程׃立即l束Q但如果此时的目标线E正在操作互斥资源、内核调用、或者是操作׃nDLL的全局变量Q可能会出现互斥资源无法释放、内核异常等现象。这里我用重叠I/0来解册个问题,在创建PIPE时用FILE_FLAG_OVERLAPPED标志Q这样用ConnectNamedPipe后会立即q回Q但U程的阻塞由{待函数WaitForSingleObject来实玎ͼ{待OVERLAPPEDl构的事件对象被讄?br>客户端主要代码:
void CMyDlg::OnSubmit()
{
// 打开道
HANDLE hPipe = CreateFile("\\\\.\\Pipe\\NamedPipe", GENERIC_READ | GENERIC_WRITE, \
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL) ;
if ( hPipe == INVALID_HANDLE_VALUE )
{
this->MessageBox ( "打开道p|Q服务器未启动,或者客L数量q多" ) ;
return ;
}
DWORD nReadByte, nWriteByte ;
char szBuf[1024] = {0} ;
// 把两个整?a,b)格式化ؓ字符?
sprintf ( szBuf, "%d %d", this->nFirst, this->nSecond ) ;
// 把数据写入管?
WriteFile ( hPipe, szBuf, strlen(szBuf), &nWriteByte, NULL ) ;
memset ( szBuf, 0, sizeof(szBuf) ) ;
// d服务器的反馈信息
ReadFile ( hPipe, szBuf, 1024, &nReadByte, NULL ) ;
// 把返回信息格式化为整?
sscanf ( szBuf, "%d", &(this->nResValue) ) ;
this->UpdateData ( false ) ;
CloseHandle ( hPipe ) ;
}
// 启动服务
void CMyDlg::OnStart()
{
CString lpPipeName = "\\\\.\\Pipe\\NamedPipe" ;
for ( UINT i = 0; i < nMaxConn; i++ )
{
// 创徏道实例
PipeInst[i].hPipe = CreateNamedPipe ( lpPipeName, PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, \
PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_WAIT, nMaxConn, 0, 0, 1000, NULL ) ;
if ( PipeInst[i].hPipe == INVALID_HANDLE_VALUE )
{
DWORD dwErrorCode = GetLastError () ;
this->MessageBox ( "创徏道错误Q? ) ;
return ;
}
// 为每个管道实例创Z个事件对象,用于实现重叠IO
PipeInst[i].hEvent = CreateEvent ( NULL, false, false, false ) ;
// 为每个管道实例分配一个线E,用于响应客户端的h
PipeInst[i].hTread = AfxBeginThread ( ServerThread, &PipeInst[i], THREAD_PRIORITY_NORMAL ) ;
}
this->SetWindowText ( "命名道实例之服务器(q行)" ) ;
this->MessageBox ( "服务启动成功" ) ;
}
// 停止服务
void CMyDlg::OnStop()
{
DWORD dwNewMode = PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_NOWAIT ;
for ( UINT i = 0; i < nMaxConn; i++ )
{
SetEvent ( PipeInst[i].hEvent ) ;
CloseHandle ( PipeInst[i].hTread ) ;
CloseHandle ( PipeInst[i].hPipe ) ;
}
this->SetWindowText ( "命名道实例之服务器" ) ;
this->MessageBox ( "停止启动成功" ) ;
}
// U程服务函数
UINT ServerThread ( LPVOID lpParameter )
{
DWORD nReadByte = 0, nWriteByte = 0, dwByte = 0 ;
char szBuf[MAX_BUFFER_SIZE] = {0} ;
PIPE_INSTRUCT CurPipeInst = *(PIPE_INSTRUCT*)lpParameter ;
OVERLAPPED OverLapStruct = { 0, 0, 0, 0, CurPipeInst.hEvent } ;
while ( true )
{
memset ( szBuf, 0, sizeof(szBuf) ) ;
// 命名道的连接函敎ͼ{待客户端的q接Q只针对NTQ?
ConnectNamedPipe ( CurPipeInst.hPipe, &OverLapStruct ) ;
// 实现重叠I/0Q等待OVERLAPPEDl构的事件对?
WaitForSingleObject ( CurPipeInst.hEvent, INFINITE ) ;
// I/0是否已经完成Q如果未完成Q意味着该事件对象是人工讄Q即服务需要停?
if ( !GetOverlappedResult ( CurPipeInst.hPipe, &OverLapStruct, &dwByte, true ) )
break ;
// 从管道中d客户端的h信息
if ( !ReadFile ( CurPipeInst.hPipe, szBuf, MAX_BUFFER_SIZE, &nReadByte, NULL ) )
{
MessageBox ( 0, "d道错误Q?, 0, 0 ) ;
break ;
}
int a, b ;
sscanf ( szBuf, "%d %d", &a, &b ) ;
pMyDlg->nFirst = a ;
pMyDlg->nSecond = b ;
pMyDlg->nResValue = a + b ;
memset ( szBuf, 0, sizeof(szBuf) ) ;
sprintf ( szBuf, "%d", pMyDlg->nResValue ) ;
// 把反馈信息写入管?
WriteFile ( CurPipeInst.hPipe, szBuf, strlen(szBuf), &nWriteByte, NULL ) ;
pMyDlg->SetDlgItemInt ( IDC_FIRST, a, true ) ;
pMyDlg->SetDlgItemInt ( IDC_SECOND, b, true ) ;
pMyDlg->SetDlgItemInt ( IDC_RESULT, pMyDlg->nResValue, true ) ;
// 断开客户端的q接Q以便等待下一客户的到?
DisconnectNamedPipe ( CurPipeInst.hPipe ) ;
}
return 0 ;
}
]]>
qͼ
讄套接口的选项?
#include <winsock.h>
int PASCAL FAR setsockopt( SOCKET s, int level, int optname,
const char FAR* optval, int optlen);
sQ标识一个套接口的描q字?
levelQ选项定义的层ơ;目前仅支持SOL_SOCKET和IPPROTO_TCP层次?
optnameQ需讄的选项?
optvalQ指针,指向存放选项值的~冲区?
optlenQoptval~冲区的长度?
注释Q?/h2>
setsockopt()函数用于Lcd、Q意状态套接口的设|选项倹{尽在不同协议层上存在选项Q但本函C定义了最高的“套接?#8221;层次上的选项。选项影响套接口的操作Q诸如加急数据是否在普通数据流中接Ӟq播数据是否可以从套接口发送等{?
有两U套接口的选项Q一U是布尔型选项Q允许或止一U特性;另一U是整Ş或结构选项。允怸个布型选项Q则optval指向非零整Ş敎ͼ止一个选项optval指向一个等于零的整形数。对于布型选项Qoptlen应等于sizeof(int)Q对其他选项Qoptval指向包含所需选项的整形数或结构,而optlen则ؓ整Ş数或l构的长度。SO_LINGER选项用于控制下述情况的行动:套接口上有排队的待发送数据,?a target=_blank>closesocket()调用已执行。参见closesocket()函数中关于SO_LINGER选项对closesocket()语义的媄响。应用程序通过创徏一个lingerl构来设|相应的操作Ҏ:
struct linger {
int l_onoff;
int l_linger;
};
Z允许SO_LINGERQ应用程序应l_onoff设ؓ非零Q将l_linger设ؓ零或需要的时|以秒为单位)Q然后调用setsockopt()。ؓ了允许SO_DONTLINGERQ亦即禁止SO_LINGERQ,l_onoff应设为零Q然后调用setsockopt()?
~省条g下,一个套接口不能与一个已在用中的本地地址捆绑Q参?a target=_blank>bind()Q。但有时会需?#8220;重用”地址。因为每一个连接都由本地地址和远端地址的组合唯一定Q所以只要远端地址不同Q两个套接口与一个地址捆绑q无大碍。ؓ了通知WINDOWS套接口实C要因Z个地址已被一个套接口使用׃让它与另一个套接口捆绑Q应用程序可在bind()调用前先讄SO_REUSEADDR选项。请注意仅在bind()调用时该选项才被解释Q故此无需Q但也无宻I一个不会共用地址的套接口讄该选项Q或者在bind()对这个或其他套接口无影响情况下设|或清除q一选项?
一个应用程序可以通过打开SO_KEEPALIVE选项Q得WINDOWS套接口实现在TCPq接情况下允怋?#8220;保持zd”包。一个WINDOWS套接口实现ƈ不是必需支持“保持zd”Q但是如果支持的话,具体的语义将与实现有养I应遵守RFC1122“InternetL要求Q通讯?#8221;中第4.2.3.6节的规范。如果有兌接由?#8220;保持zd”而失效,则进行中的Q何对该套接口的调用都以WSAENETRESET错误q回Q后l的M调用以WSAENOTCONN错误q回?
TCP_NODELAY选项止Nagle法。Nagle法通过未认的数据存入缓冲区直到蓄一个包一起发送的ҎQ来减少L发送的零碎数据包的数目。但对于某些应用来说Q这U算法将降低pȝ性能。所以TCP_NODELAY可用来将此算法关闭。应用程序编写者只有在切了解它的效果q确实需要的情况下,才设|TCP_NODELAY选项Q因|后对网l性能有明昄负面影响。TCP_NODELAY是唯一使用IPPROTO_TCP层的选项Q其他所有选项都用SOL_SOCKET层?
如果讄了SO_DEBUG选项QWINDOWS套接口供应商被鼓励(但不是必需Q提供输出相应的调试信息。但产生调试信息的机制以及调试信息的形式已超出本规范的讨围?
setsockopt()支持下列选项。其?#8220;cd”表明optval所指数据的cd?
选项 cd 意义
SO_BROADCAST BOOL 允许套接口传送广播信息?
SO_DEBUG BOOL 记录调试信息?
SO_DONTLINER BOOL 不要因ؓ数据未发送就d关闭操作。设|本选项相当于将SO_LINGER的l_onoff元素|ؓ零?
SO_DONTROUTE BOOL 止选径Q直接传送?
SO_KEEPALIVE BOOL 发?#8220;保持zd”包?
SO_LINGER struct linger FAR* 如关闭时有未发送数据,则逗留?
SO_OOBINLINE BOOL 在常规数据流中接收带外数据?
SO_RCVBUF int 为接收确定缓冲区大小?
SO_REUSEADDR BOOL 允许套接口和一个已在用中的地址捆绑Q参见bind()Q?
SO_SNDBUF int 指定发送缓冲区大小?
TCP_NODELAY BOOL 止发送合q的Nagle法?
setsockopt()不支持的BSD选项有:
选项?cd 意义
SO_ACCEPTCONN BOOL 套接口在监听?
SO_ERROR int 获取错误状态ƈ清除?
SO_RCVLOWAT int 接收低水印?
SO_RCVTIMEO int 接收时?
SO_SNDLOWAT int 发送低U水印?
SO_SNDTIMEO int 发送超时?
SO_TYPE int 套接口类型?
IP_OPTIONS 在IP头中讄选项?
q回|
若无错误发生Qsetsockopt()q回0。否则的话,q回SOCKET_ERROR错误Q应用程序可通过WSAGetLastError()获取相应错误代码?
错误代码Q?
WSANOTINITIALISEDQ在使用此API之前应首先成功地调用WSAStartup()?
WSAENETDOWNQWINDOWS套接口实现检到|络子系l失效?
WSAEFAULTQoptval不是q程地址I间中的一个有效部分?
WSAEINPROGRESSQ一个阻塞的WINDOWS套接口调用正在运行中?
WSAEINVALQlevel值非法,或optval中的信息非法?
WSAENETRESETQ当SO_KEEPALIVE讄后连接超时?
WSAENOPROTOOPTQ未知或不支持选项。其中,SOCK_STREAMcd的套接口不支持SO_BROADCAST选项QSOCK_DGRAMcd的套接口不支持SO_DONTLINGER 、SO_KEEPALIVE、SO_LINGER和SO_OOBINLINE选项?
WSAENOTCONNQ当讄SO_KEEPALIVE后连接被复位?
WSAENOTSOCKQ描q字不是一个套接口?
用法
1.讄调用closesocket()?仍可l箋重用该socket。调用closesocket()一般不会立卛_闭socketQ而经历TIME_WAIT的过E?
BOOL bReuseaddr = TRUE;
setsockopt( s, SOL_SOCKET, SO_REUSEADDR, ( const char* )&bReuseaddr, sizeof( BOOL ) );
2. 如果要已l处于连接状态的soket在调用closesocket()后强制关闭,不经历TIME_WAIT的过E:
BOOL bDontLinger = FALSE;
setsockopt( s, SOL_SOCKET, SO_DONTLINGER, ( const char* )&bDontLinger, sizeof( BOOL ) );
3.在send(),recv()q程中有时由于网l状늭原因Q收发不能预期进?可以讄收发旉Q?
int nNetTimeout = 1000; //1U?
//发送时?
setsockopt( socket, SOL_SOCKET, SO_SNDTIMEO, ( char * )&nNetTimeout, sizeof( int ) );
//接收旉
setsockopt( socket, SOL_SOCKET, SO_RCVTIMEO, ( char * )&nNetTimeout, sizeof( int ) );
4.在send()的时候,q回的是实际发送出ȝ字节(同步)或发送到socket~冲区的字节(异步)Q系l默认的状态发送和接收一ơؓ8688字节(U?
?.5K)Q在实际的过E中如果发送或是接收的数据量比较大Q可以设|socket~冲区,避免send(),recv()不断的@环收发:
// 接收~冲?
int nRecvBuf = 32 * 1024; //讄?2K
setsockopt( s, SOL_SOCKET, SO_RCVBUF, ( const char* )&nRecvBuf, sizeof( int ) );
//发送缓冲区
int nSendBuf = 32*1024; //讄?2K
setsockopt( s, SOL_SOCKET, SO_SNDBUF, ( const char* )&nSendBuf, sizeof( int ) );
5.在发送数据的Ӟ不执行由pȝ~冲区到socket~冲区的拯Q以提高E序的性能Q?
int nZero = 0;
setsockopt( socket, SOL_S0CKET, SO_SNDBUF, ( char * )&nZero, sizeof( nZero ) );
6.在接收数据时Q不执行socket~冲区的内容拯到系l缓冲区Q?
int nZero = 0;
setsockopt( s, SOL_S0CKET, SO_RCVBUF, ( char * )&nZero, sizeof( int ) );
7.一般在发送UDP数据报的时候,希望该socket发送的数据hq播Ҏ:
BOOL bBroadcast = TRUE;
setsockopt( s, SOL_SOCKET, SO_BROADCAST, ( const char* )&bBroadcast, sizeof( BOOL ) );
8.在clientq接服务器过E中Q如果处于非d模式下的socket在connect()的过E中可以讄connect()延时,直到accpet()被调?此设|只
有在非阻塞的q程中有显著的作用,在阻塞的函数调用中作用不?
BOOL bConditionalAccept = TRUE;
setsockopt( s, SOL_SOCKET, SO_CONDITIONAL_ACCEPT, ( const char* )&bConditionalAccept, sizeof( BOOL ) );
9.如果在发送数据的q程中send()没有完成Q还有数据没发送,而调用了closesocket(),以前一般采取的措施是shutdown(s,SD_BOTH),但是?
据将会丢失?
某些具体E序要求待未发送完的数据发送出d再关闭socketQ可通过讄让程序满求:
struct linger {
u_short l_onoff;
u_short l_linger;
};
linger m_sLinger;
m_sLinger.l_onoff = 1; //在调用closesocket()时还有数据未发送完Q允许等?
// 若m_sLinger.l_onoff=0;则调用closesocket()后强制关?
m_sLinger.l_linger = 5; //讄{待旉?U?
setsockopt( s, SOL_SOCKET, SO_LINGER, ( const char* )&m_sLinger, sizeof( linger ) );
]]>
sQ一个标识套接口的描q字?
cmdQ对套接口s的操作命令?
argpQ指向cmd命o所带参数的指针?
注释Q? 本函数可用于M状态的M套接口。它用于获取与套接口相关的操作参敎ͼ而与具体协议或通讯子系l无兟뀂支持下列命令: FIONBIOQ允许或止套接口s的非d模式。argp指向一个无W号长整型。如允许非阻塞模式则非零Q如止非阻塞模式则为零。当创徏一个套接口Ӟ它就处于d模式Q也是说非d模式被禁止)。这与BSD套接口是一致的。WSAAsynSelect()函数套接口自动讄为非d模式。如果已对一个套接口q行了WSAAsynSelect() 操作Q则M用ioctlsocket()来把套接口重新设|成d模式的试囑ְ以WSAEINVALp|。ؓ了把套接口重新设|成d模式Q应用程序必首先用WSAAsynSelect()调用QIEvent参数|ؓ0Q来至WSAAsynSelect()? FIONREADQ确定套接口s自动d的数据量。argp指向一个无W号长整型,其中存有ioctlsocket()的返回倹{如果s是SOCKET_STREAMcdQ则FIONREADq回在一ơrecv()中所接收的所有数据量。这通常与套接口中排队的数据总量相同。如果S是SOCK_DGRAM 型,则FIONREADq回套接口上排队的第一个数据报大小? SIOCATMARKQ确实是否所有的带外数据都已被读入。这个命令仅适用于SOCK_STREAMcd的套接口Q且该套接口已被讄为可以在U接收带外数据(SO_OOBINLINEQ。如无带外数据等待读入,则该操作q回TRUE真。否则的话返回FALSE假,下一个recv()或recvfrom()操作检?#8220;标记”前一些或所有数据。应用程序可用SIOCATMARK操作来确定是否有数据剩下。如果在“紧?#8221;Q带外)数据前有常规数据Q则按序接收q些数据Q请注意Qrecv()和recvfrom()操作不会在一ơ调用中h常规数据与带外数据)。argp指向一个BOOL型数Qioctlsocket()在其中存入返回倹{? 兼容性: 本函CؓBerkeley套接口函数ioctl()的一个子集。其中没有与FIOASYNC{h的命令,SIOCATMARK是套接口层次支持的唯一命o? q回| 成功后,ioctlsocket()q回0。否则的话,q回SOCKET_ERROR错误Q应用程序可通过WSAGetLastError()获取相应错误代码? 错误代码Q? WSANOTINITIALISEDQ在使用此API之前应首先成功地调用WSAStartup()? WSAENETDOWNQWINDOWS套接口实现检到|络子系l失效? WSAEINVALQcmd为非法命令,或者argp所指参C适用于该cmd命oQ或者该命o 不适用于此U类型的套接口? WSAEINPROGRESSQ一个阻塞的WINDOWS套接口调用正在运行中? WSAENOTSOCKQ描q字不是一个套接口? 参见Q? socket(), setsockopt(), getsockopt(), WSAAsyncSelect(). 该命?nbsp; 不适用于此U类型的套接口?nbsp; WSAEINPROGRESSQ一个阻塞的WINDOWS套接口调用正在运行中?nbsp; WSAENOTSOCKQ描q字不是一个套接口?
]]>
通信模块?br>
通信关系?br>
其中有不的地方, 希望朋友们提出意?