网络编程若干点


定地?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

除了这点?还需要哪些改进?

效率:如果我们用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




原文地址:https://www.cnblogs.com/xianqingzh/p/1565579.html