定地?tcp、udp传输数据的时候。都需要一固定的地址:ip地址及其端口号。WinSock中,就用 SockAddr_in来指定。
struct sockaddr_in
{
short sin_family
u_short sin_port
struct in_addr sin_addr
char sin_zero[8]
}
//
in_addr 可以把字符串编程点状的ip地址
inet_addr 则相反
声明如下:
unsigned long inet_addr
{
const char* FAR* p
}
看了管道,知道了个大概,可是那么浅层次的了解。又无法解决问题。其实namedPip归根到底是提供一种简单的服务端/客户端模型来建立对某一路径的文件的操作(有byte模式和消息模式)
基本API如下,msdn有一堆解释:
首先创建一个指定名字的管道,调用如下API (具体参数查MSDN):
HANDLE CreateNamedPipe
创建一个新线程(CreateThread),轮循管道中是否有新消息到来,新线程中调用如下两个函数:
BOOL ConnectNamedPipe
BOOL DisconnectNamedPipe
//新线程过程
DWORD WINAPI InquiryPipeThreadProc(LPVOID lpParameter)
{
while(1)//堵死
{
if(TRUE!=ConnectNamedPipe(...))
{
//查询出错原因
}
ReadFile(...);
DisconnectNamedPipe(...);
PostMessage(...);//您可以将管道中收的内容发送给窗口过程的消息队列
}
return 1;
}
---上面的东西远远不足,有哪些不足呢?
首先,我们无法控制哪些人可以通过管道进行访问,哪些人需要被阻止,也就是DACL-----这也是管道的精髓。如果仅仅是普通的建立文件的读取关系的话,CreateFile不是就可以了吗?
那么如何建立DACL呢?
SECURITY_ATTRIBUTE 归根到底是初始化一个结构体去替代默认的情况
附代码:未测试
Code
#include<windows.h>
#include <iostream>
using namespace std;
void main()
{
//CREAE A SECURITY_ATTRIBUTE
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd; //
if(InitializeSecurityDescriptor(&sa,SECURITY_DESCRIPTOR_REVISION));//the second param is using for alter the normol security level
{
cout<<"fail to initial the sa"<<endl;
return;
}
else
{
if(SetSecurityDescriptorSacl(&sd,TRUE,NULL,FALSE))
{
cout<<"SET error"<<endl;
return;
}
}
sa.nLength=sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor=&sd;
sa.bInheritHandle=TRUE;
HANDLE hPipHandele;
DWORD dwBtyeRead;
CHAR buffer[356];
if ((hPipHandele=CreateNamedPipe("\\\.\\share\\test.txt",PIPE_ACCESS_DUPLEX,PIPE_READMODE_BYTE|PIPE_TYPE_BYTE,2,100,100,4000,sa)==INVALID_HANDLE_VALUE)
{
cout<<"error"<<endl;
}
else
{
ConnectNamedPipe(hPipHandele,NULL);
cout<<"pip connecting"<<endl;
//开始读文件按
if (ReadFile(hPipHandele,buffer,sizeof(buffer),&dwBtyeRead,0))
{
cout<<"reading File"<<endl;
}
DisconnectNamedPipe(hPipHandele);
}
CloseHandle(hPipHandele);
除了这点?还需要哪些改进?
效率:如果我们用namePiped中,默认的情况是实时的,我们可以采用多线程来让它可以服务多个对象
当然到现在还远远不够,最多我们仅仅了解什么是pip和构建的时候需要注意到的地方。但是对于它的实际用途还是不知道。那么pipe的实际用途是什么?
一、并不是翻译MSDN
二、管道是用来通信用的(消息队列知道不?)
三、通信的过程当然需要读取和发送,读取的内容当然是你向管道写入的内容
四、试问一下一个WEB程序想跟我们的应用程序进行通信你是如何做到的(讯雷,WEB中右键点击...)
五、Window机制看来你还不了解,其实Window把所有设备都当做文件来进行操作,主要是为了建立统一接口。
-(http://bbs.pediy.com/archive/index.php?t-63953.html)
看看第四点:这个我也不大明白。web迅雷中不是一般都要定位到某一个驱动器吗,比如E:。可是管道的话。一般都是利用UNC来进行标识的;eg: \\server\\Pipe\\
六、有一些初学者估计对socket 和socket_in有些模糊,其实socket_in里面仅仅保存要连接的具体的端口、ip信息。
而socket更多的是确定工作域、还有套用的协议。两个结合在一起绑定才是一个具体的通讯环境。
七、listent的backlog代表的是能够缓存进处理队列的连接数,但是多少个客户端发起的请求却无法明白。
八、accept(SOCKET,(SOCKETADDR)FAR*,int) accept函数中的第二个参数是连接过来的客户端的信息,
accept()用来接受参数s的socket连线。参数s的socket必需先经bind()、listen()函数处理过,当有连线进来时accept()会返回一个新的socket处理代码,往后的数据传送与读取就是经由新的socket处理,而原来参数s的socket能继续使用accept()来接受新的连线要求。连线成功时,参数addr所指的结构会被系统填入远程主机的地址数据,参数addrlen为scokaddr的结构长度。关于结构sockaddr的定义请参考bind()。(FROM:http://www.embeded.cn/online/linux_function/14.html)
九、send(SOCKET,(char*)buf,int len,int flag)
前面3个参数比较熟悉,后面的那个flag参数一般大家会默认成0,但是实际情况下,很多开发对最后的那个参数要求会比较高。
flag的取值:0 、MSG_DONTROUTE、MSG_OOB
MSG_DONTROUTE 就是不要把这个消息路由出去。 比如你有一个客户端,这个客户端是用户查询移动/联通的话费信息,那么,你可能就会设置这个属性了---为了提高安全性。
MSG_OOB 预示数据应该被带外发送
什么是带外发送(out-of-band),, "out-of-band" refers to communications which occur outside of a previously established communication method or channel. (http://en.wikipedia.org/wiki/Out-of-band)
比如六级考试,一般的考生都是接收正常轨迹的听力对话,你带一个耳机接收的却是外面的答案;或者你参加一个聚会,你和大多数人都是很开朗的谈话,唯独对某一个美女或是发短信、或是窃窃私语。反正相对于整个整体,你采用一种比较私密化的方式传输你的那些数据--这些数据你并不希望被所有的人都知道。
如果在一个计算机管理系统中。它或许就代表这么一种途径:你在软硬件都崩溃的情况下。采取一种可以另类的进入你的计算机管理体系。
注意:out-of—band 并不意味着这些数据有更高的优先级或者更加紧急。
接下来,可以说说send这个函数怎么走流程:首先send函数先对 s中缓冲区的长度与len进行比较,如果s<len.就直接给出SOCKET_ERROR。如果len<s,那么会再比较 s中缓冲区是否有数据或者正在发送数据,如果真正发送数据,那么就进行等待,如果有数据但是未进行发送。那么再次比较剩余的缓冲区容量大小与len对比,如果sizeof(缓冲区)<len,那么就乖乖的等待数据发送完,否则就直接把数据copy到缓冲区中发送。copy成功的话返回copy了的数据量大小。出错的话返回SOCKET_ERROR,记住,具体的发送出去是协议的事情。如果发送出去后恰好遇到网络中断。那么下一个socket函数比如Receive就会接收到SOCKET_ERROR的错误信息,但是对于Send来说。copy成功就没它的事情了。
(http://blog.chinaunix.net/u2/62281/showart_524826.html 可以看看补充一下
recv(SOCKET s,char* szBuf,int len,int nflag) 过程也是一样,当s中没有数据或者正在接收数据的时候,那么它先按兵不懂,时机到了(有数据且不处于接收状态),它就把s中缓冲区的数据copy到szBuf中,如果szBuf一次吃不消,就分几次去recv。
recv的nflag的取值 有 0、MSG_PEEK、MSG_OOB
取值为0是一般情况,取值为MSG_PEEK表示把缓冲区的数据copy到szBuf的时候同时会附带待发字节数,并且不会删除缓存区的数据。慢慢的发送端会减少发送窗口的容量。
那什么时候会有MSG_PEEK的时候呢? PEEK有偷窥的意味,这种方式允许你在不需要copy完数据才能读数据进行读取,相反你可以从缓冲区读取数据。对数据进行预处理。为了安全的处理某些协议,就必须取这个参数了。
可以看看WSARecv微软对其进行了一些扩充。
看看一段代码 (copy from window network programing)
char sendBuf[2048];
int nSend=2048;
int nLeft=2048;
int sendTotal=0;
while(nLeft>0)
{
nRet=send(s,sendBuf,nSend,0);
if(nRet==SOCKET_ERROR)
{
//Error
}
nLeft-=nRet;
sendTotal+=nRet;
}
//上面的代码对于流套接字的话,意义不大,因为流套接字的话数据是连续的。
哎,写了很多没保存。。
直接跳过说重叠IO。
为什么会有重叠I/0.它有什么用。怎么来实现它,实现它有哪些注意点,现实当中有哪些注意点?
1,为什么会有重叠I/O
bool readfile(
handle hfile, // handle to file
lpvoid lpbuffer, // data buffer
dword nnumberofbytestoread, // number of bytes to read
lpdword lpnumberofbytesread, // number of bytes read
lpoverlapped lpoverlapped // overlapped buffer
);
如 果我们在createfile的时候没有使用file_flag_overlapped 标志,同时在调用readfile的时候把lpoverlapped lpoverlapped 这个参数设置的是null,那么readfile这个函数的调用一直要到读取完数据指定的数据后才会返回,如果没读取完,就会阻塞在这里。writefile都是这样的。这样在读写大文件的时候,我们很多时间都浪费在等待readfile和writefile的返回 上面。
如果readfile和writefile是往管道里读写数据,那么有可能阻塞得更久,导致程序性能下降。为了解决这个问题,windows引进了 重叠io的概念,同样是上面的readfile和writefile,如果在createfile的时候设置了 file_flag_overlapped ,那么在调用readfile和writefile的时候就可以给他们最后一个参数传递一个 overlapped结构。这样readfile或者writefile的调用马上就会返回,这时候你可以去做你要做的事,系统会自动替你完成 readfile或者writefile,在你调用了readfile或者writefile后,你继续做你的事,系统同时也帮你完成readfile或 writefile的操作,这就是所谓的重叠。使用重叠io还有一个好处,就是你可以同时发出几个readfile或者writefile的调用,然后用 waitforsingleobject或者waitformultipleobjects来等待操作系统的操作完成通知,在得到通知信号后,就可以用 getoverlappedresult来查询io调用的结果。
(摘自http://blog.csdn.net/metasearch/archive/2008/03/05/2148226.aspx)
重叠i/o就是能够同时以多个线程处理多个i/o,其实你自己开多个线程也可以处理多个i/o,当然系统内部优化以后肯定性能要比你的强,呵呵。
我只是简单的说了一下重叠[overlapped]没从代码的角度给你分析。希望你能对重叠io有所理解。看看windows网络编程,上面不是有模型嘛
最后提一下重叠模型的缺点,他为每一个io请求都开了一根线程,当同时有1000个请求发生,那么系统处理线程上下文[context]切换也是非常耗时的,所以这也就引发了完成端口模型iocp,用线程池来解决这个问题,我就不多说了、
3.如何实现?
Code
//1、创建一个套接字,开始在指定的端口上监听连接请求。
//2、接收一个入站的连接请求。
//3、为接受的套接字创建新的WSAOVERLAPPED结构,并分配事件对象句柄。
//4、以WSAOVERLAPPED结构为参数,在套接字上投递WSARecv调用。
//5、将所有接受套接字的事件组建事件数组,并调用WSAWaitForMultipleEvents函数,等待与重叠调用关联在一起的事件受信。
//6、使用WSAGetOverlappedResult函数,判断重叠调用的返回状态。
//7、重新组建事件数组。
//8、在套接字上重投递WSARecv请求。
//9、重复5~8。
//
//例子:初步封装了OverLapped类
/*SockObject*/
#include
class SockObject
{
public:
SOCKET m_sock;
int m_operatNum;
public:
SockObject(void );
SockObject(SOCKET mySock);
SockObject(SockObject&mySockObject);
~SockObject(void );
};
SockObject::SockObject(SOCKET mySock)
{
m_sock=mySock;
m_operatNum=0;
}
SockObject::SockObject(SockObject&mySockObject)
{
m_sock=mySockObject.m_sock;
m_operatNum=mySockObject.m_operatNum;
}
/******************************************************************************
*数据结构名称:OverObject
*功能:记录一个套接字的一个操作、一个事件和一个重叠I/O的关联
*****************************************************************************/
class OverObject
{
public:
SOCKET m_sock;/*绑定的套接字*/
OVERLAPPED m_overlapped;/*绑定的重叠I/O*/
char* m_buf;/*用于存放数据的缓冲区*/
int m_len;/*缓冲区的长度*/
int m_operation;/*套接字针对的操作*/
public:
bool operator==(constOverObject&myOverObject)const;
public:
OverObject(void );
OverObject(const OverObject &myOverObject);
OverObject(SOCKET mySock,int myLen);
~OverObject(void );
};
/*定义指向重叠对象的指针类型*/
typedef OverObject* PtrOverObject;
OverObject::~OverObject(void )
{
deletem_buf;
}
/********************************************************************************
*函数介绍:本函数是OverObject类的复制构造函数。
*********************************************************************************/
OverObject::OverObject(const OverObject &myOverObject)
{
m_sock=myOverObject.m_sock;
m_overlapped=myOverObject.m_overlapped;
m_buf=newchar[myOverObject.m_len];
strcpy(m_buf,myOverObject.m_buf);
m_len=myOverObject.m_len;
m_operation=myOverObject.m_operation;
}
/********************************************************************************
*函数介绍:本函数是OverObject类带参数的构造函数。
*********************************************************************************/
OverObject::OverObject(SOCKET mySock,int myLen)
{
m_sock=mySock;
m_buf=newchar[myLen];
m_len=myLen;
m_overlapped.hEvent=::WSACreateEvent();
}
/********************************************************************************
*函数介绍:本函数是OverObject类的==运算符重载函数
*********************************************************************************/
bool OverObject::operator==(constOverObject&myOverObject)const
{
if(this->m_sock==myOverObject.m_sock&&this->m_operation==myOverObject.m_operation&&this->m_len==myOverObject.m_len&&!strcmp(this->m_buf,myOverObject.m_buf))
{
coutoverObjects;/*需要维护的所有重叠I/O*/
vectoreventArray;/*所有重叠I/O所对应的事件组成的数组,作为等待函数的参数*/
vectorsockArray;/*需要维护的所有套接字,当操作为零时关闭套接字*/
public:
list::iterator GetOverObject(SOCKET mySock,int myLen);
void FreeOverObject(list::iterator myPtrOverObject);
list::iterator Overlapped::FindOverObject(HANDL EmyEvent);
void RebuildEventArray();
void CreateAcceptEvent();
void SetAcceptEvent();
void ResetAcceptEvent();
bool IsAcceptEvent(int index);
bool PostRecv(list::iterator myPtrOverObject);
bool PostSend(list::iterator myPtrOverObject);
bool PostAccept(list::iterator myPtrOverObject);
Overlapped(void );
~Overlapped(void );
void InitSocket();
};
/********************************************************************************
*函数介绍:创建重叠对象的类对象,并插入重叠对象链表中。
*********************************************************************************/
list::iterator Overlapped::GetOverObject(SOCKET mySock,int myLen)
{
OverObjectlocalOverObject(mySock,myLen);
overObjects.push_back(localOverObject);
eventArray.push_back(localOverObject.m_overlapped.hEvent);
list::iterator ret=overObjects.end();
ret--;
return ret;
}
/********************************************************************************
*函数介绍:释放重叠对象链表中指定的重叠对象。
*********************************************************************************/
void Overlapped::FreeOverObject(list::iterator myPtrOverObject)
{
overObjects.erase(myPtrOverObject);
}
/********************************************************************************
*函数介绍:从重叠对象列表中查找指定事件所对应的重叠对象。
*********************************************************************************/
list::iterator Overlapped::FindOverObject(HANDL EmyEvent)
{
list::iterator localIerator;
for(localIerator=overObjects.begin();localIerator!=overObjects.end();localIerator++)
{
if(localIerator->m_overlapped.hEvent==myEvent)
{
break;
}
}
return localIerator;
}
/********************************************************************************
*函数介绍:遍历重叠对象列表,重建重叠对象列表所对应的事件数组。
*********************************************************************************/
void Overlapped::RebuildEventArray()
{
eventArray.clear();
list::iterator overObjIterator;
overObjIterator=overObjects.begin();
for(overObjIterator;overObjIterator!=overObjects.end();++overObjIterator)
{
eventArray.push_back(overObjIterator->m_overlapped.hEvent);
}
}
/********************************************************************************
*函数介绍:投放接受操作,即将指定套接字的Recv操作与重叠I/O对象关联起来。
*********************************************************************************/
bool Overlapped::PostRecv(list::iterator myPtrOverObject)
{
myPtrOverObject->m_operation=OP_READ;
DWORD dwBytes;
DWORD dwFlags=0;
WSABUF buf;
buf.buf=myPtrOverObject->m_buf;
buf.len=myPtrOverObject->m_len;
memset(buf.buf,0,buf.len);
if(::WSARecv(myPtrOverObject->m_sock,&buf,1,&dwBytes,&dwFlags,&myPtrOverObject->m_overlapped,NULL)!=NO_ERROR)
{
if(::WSAGetLastError()!=WSA_IO_PENDING)
{
return false;
}
}
return true;
}
/********************************************************************************
*函数介绍:投放发送操作,即将指定套接字的Send操作与重叠I/O对象关联起来。
*********************************************************************************/
bool Overlapped::PostSend(list::iterator myPtrOverObject)
{
myPtrOverObject->m_operation=OP_WRITE;
DWORD dwBytes;
DWORD dwFlags=0;
WSABUF buf;
buf.buf=myPtrOverObject->m_buf;
buf.len=myPtrOverObject->m_len;
if(::WSASend(myPtrOverObject->m_sock,&buf,1,&dwBytes,dwFlags,&myPtrOverObject->m_overlapped,NULL)!=NO_ERROR)
{
if(::WSAGetLastError()!=WSA_IO_PENDING)
{
return false;
}
}
return true;
}
/********************************************************************************
*函数介绍:创建accept函数完成事件,用于处理accepe后等待函数的等待事件句柄数组发
生变化,若此时无事件触发,等待事件句柄数组仍以原来的事件句柄数组为依
据等待。
*********************************************************************************/
void Overlapped::CreateAcceptEvent()
{
//标志套接字,用于触发accept完成事件。
SOCKET myClient=::WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED);
list::iterator acceptIterator=GetOverObject(myClient,512);
RebuildEventArray();
}
/********************************************************************************
*函数介绍:当accept函数完成时,重置accept所对应的事件,从而使得等待函数能够在改
变后的事件句柄数组上等待。
*********************************************************************************/
void Overlapped::SetAcceptEvent()
{
::SetEvent(eventArray.front());
}
void Overlapped::ResetAcceptEvent()
{
::ResetEvent(eventArray.front());
}
bool Overlapped::IsAcceptEvent(int index)
{
if(index==0)
{
return true;
}
else
{
return false;
}
}
/*主程序*/
#include"Overlapped.h"
#include
#include
bool OperateFunction(PtrOverObjectmyPtrOverObject);
Uint WINAPIServerThread(Pvoid pvParam);
OverlappedmyOverlapped;
int main()
{
WSADATAwsaData;
if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
{
cout::iteratorlocalIterator=myOverlapped.GetOverObject(myClient,512);
myOverlapped.PostRecv(localIterator);
myOverlapped.RebuildEventArray();
myOverlapped.SetAcceptEvent();
}
charch;
cin>>ch;
return 0;
}
/********************************************************************************
*函数介绍:数据处理函数,按照不同操作类型,处理数据的发送或接受。
*********************************************************************************/
bool OperateFunction(list::iterator myOverObjectIterator)
{
DWORD dwTrans;
DWORD dwFlags;
bool ret=::WSAGetOverlappedResult(myOverObjectIterator->m_sock,&(myOverObjectIterator->m_overlapped),&dwTrans,false,&dwFlags);
if(!ret)
{
if(myOverObjectIterator->m_sock!=INVALID_SOCKET )
{
closesocket(myOverObjectIterator->m_sock);
}
coutm_operation)
{
caseOP_READ:/*接收数据完成*/
if(dwTrans>0)
{
coutm_buf::iteratorlocalIterator=myOverlapped.GetOverObject(myOverObjectIterator->m_sock,512);
localIterator->m_len=myOverObjectIterator->m_len;
strcpy(localIterator->m_buf,myOverObjectIterator->m_buf);
myOverlapped.PostSend(localIterator);
myOverlapped.RebuildEventArray();
return true;
}
else
{
closesocket(myOverObjectIterator->m_sock);
myOverlapped.FreeOverObject(myOverObjectIterator);
myOverlapped.RebuildEventArray();
cout0)
{
return true;
}
else
{
closesocket(myOverObjectIterator->m_sock);
myOverlapped.FreeOverObject(myOverObjectIterator);
myOverlapped.RebuildEventArray();
return false;
}
break;
}
}
/********************************************************************************
*函数介绍:服务线程函数,平常处于等待状态,完成数据处理。
*********************************************************************************/
Uint WINAPIServerThread(Pvoid pvParam)
{
while(true)
{
int index;
DWORD eventNum=(DWORD )(myOverlapped.eventArray.size());
index=::WSAWaitForMultipleEvents(eventNum,&(myOverlapped.eventArray[0]),false,WSA_INFINITE,false);
if(index==WSA_WAIT_FAILED)
{
cout::iteratornowIterator=(myOverlapped.FindOverObject(myOverlapped.eventArray[index]));
if(nowIterator!=NULL)
{
bool ret=OperateFunction(nowIterator);
if(ret)
{
::WSAResetEvent(myOverlapped.eventArray[index]);
myOverlapped.PostRecv(nowIterator);
}
}
}
}
return 0;
}