• 网络编程若干点



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




  • 相关阅读:
    XCode5中新建工程后强制使用了ARC,如何去掉?
    面向对象程序的设计原则--Head First 设计模式笔记
    ios控件自定义指引
    iOS UITableViewDelegate && UITableViewDataSource 执行顺序
    awakeFromNib方法和viewDidLoad方法区别
    ios 视图的旋转及应用
    线段树模板 (刘汝佳)
    poj 3468
    hdu 2829(四边形优化 && 枚举最后一个放炸弹的地方)
    poj 3517(约瑟夫环问题)
  • 原文地址:https://www.cnblogs.com/xianqingzh/p/1565579.html
Copyright © 2020-2023  润新知