一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

IOCP中多次投遞WSASend

 3dC 2014-02-09

      關(guān)于IOCP中是否可以對(duì)同一socket連續(xù)投遞的疑問已經(jīng)很久了,主要的疑問在wsaSend是否可以保證數(shù)據(jù)的完整發(fā)送,是否會(huì)出現(xiàn)部分發(fā)送成功的情況?

      網(wǎng)上大多數(shù)的建議都是WSASEND采用線性模式,即建立一個(gè)發(fā)送緩沖,當(dāng)上一次send完成之后,再進(jìn)行下一次的投遞。那么WSASEND什么情況下會(huì)出現(xiàn)部分發(fā)送呢?

     在MSDN中IOCP的列子是對(duì)得到的發(fā)送的字節(jié)值進(jìn)行了判斷的,而在wsaSend函數(shù)的描述中也有這樣一句:Note  The successful completion of a WSASend does not indicate that the data was successfully delivered.

   我首先想到的是當(dāng)發(fā)送緩沖區(qū)不足的時(shí)候,會(huì)不會(huì)造成wsaSend部分發(fā)送返回。做了個(gè)實(shí)驗(yàn),連續(xù)發(fā)送10M的數(shù)據(jù)(肯定大于緩沖區(qū)了)。第一次直接返回成功(對(duì)端并未進(jìn)行Recv),第二次返回IO_PENDING.看來不是這樣的。查了《windows 網(wǎng)絡(luò)編程技術(shù)》其中有這樣一段話:

    When an application makes a send call, if there is sufficient buffer space, the data is copied into the socket's send buffers, the call completes immediately with success, and the completion is posted. On the other hand, if the socket's send buffer is full, then the application's send buffer is locked and the send call fails withWSA_IO_PENDING. After the data in the send buffer is processed (for example, handed down to TCP for processing), then Winsock will process the locked buffer directly. That is, the data is handed directly to TCP from the application's buffer and the socket's send buffer is completely bypassed。

   當(dāng)發(fā)送緩沖不足的時(shí)候,會(huì)內(nèi)存鎖定,我另一端調(diào)用recv,收到wsasend的完成信號(hào)時(shí),發(fā)送的字節(jié)數(shù)=要發(fā)送的字節(jié)數(shù),并沒有部分發(fā)送。

  下面是我網(wǎng)上找到的一片帖子忘了出自哪里了。

--------------------------------------------------------------------------------------------------------- 

   對(duì)于WSASend使用,一直有些疑惑,雖然對(duì)開發(fā)影響不大,但是總是很別扭。


疑惑1:


按照MSDN的說法:

1)不必等待WSASend發(fā)送成功,可以連續(xù)調(diào)用WSASend發(fā)送數(shù)據(jù)。

2)可以給WSASend提供一個(gè)Buffer數(shù)組,一次發(fā)送多個(gè)不連續(xù)的緩沖區(qū)

3)使用WSASend發(fā)送成功后,提供的數(shù)據(jù)不保證能夠被全部發(fā)送出去


這樣是否存在這樣的問題:

假如我連續(xù)投遞了5個(gè)WSASend發(fā)送數(shù)據(jù),如果第3個(gè)WSASend的數(shù)據(jù)沒有完全發(fā)送出去,而第4個(gè)WSASend又被接受,豈不是導(dǎo)致錯(cuò)誤,因?yàn)橄到y(tǒng)無法得知我的第4個(gè)WSASend何時(shí)投遞。


如果第3個(gè)發(fā)送數(shù)據(jù)的第2個(gè)參數(shù)是一個(gè)Buffer數(shù)組,我為了發(fā)送剩余數(shù)據(jù),豈不要檢查到底發(fā)送了幾個(gè)Buffer?


為了保險(xiǎn)起見,我的項(xiàng)目中沒有連續(xù)投遞過WSASend,也沒有使用過多Buffer的功能,而是老老實(shí)實(shí)地在WSASend發(fā)送成功后,檢查數(shù)據(jù)是否發(fā)送完全,如果沒有,繼續(xù)發(fā)送剩余數(shù)據(jù),直到一次數(shù)據(jù)全部發(fā)送出去后,才發(fā)送下一個(gè)數(shù)據(jù)包。


疑惑2:


數(shù)據(jù)發(fā)送成功的含義(WSASend調(diào)用返回STATUS_SUCCESS或完成例程被調(diào)用或完成例程被調(diào)用或在完成端口上dequeue了一個(gè)完成包),可能情況:


1)數(shù)據(jù)被提交到tdi Client(AFD),就認(rèn)為數(shù)據(jù)發(fā)送成功了

2)數(shù)據(jù)被提交到到tdi Server(如TCP),加入tcp的發(fā)生隊(duì)列,就認(rèn)為數(shù)據(jù)被發(fā)送成功了

3)數(shù)據(jù)被提交到網(wǎng)卡的發(fā)送緩沖區(qū),就認(rèn)為數(shù)據(jù)發(fā)送成功了

4)數(shù)據(jù)被網(wǎng)卡發(fā)送出去,就認(rèn)為發(fā)送成功了

5)數(shù)據(jù)被對(duì)方成功接收,收到確認(rèn),就表示發(fā)送成功了。

以上情況到底屬于那一種呢?按照MSDN的說法,發(fā)送請(qǐng)求被傳輸層消費(fèi)掉了,就認(rèn)為發(fā)送成功了,不知大家是如何理解這句話。


對(duì)于以上兩個(gè)疑問,網(wǎng)絡(luò)上也是沒有一個(gè)定論,看來要搞清楚以上兩個(gè)問題,不深入windows源碼是無解了。


先說說WSASend的調(diào)用過程吧(基于NT4源碼),源碼就不貼了,免得MS找麻煩:


WSASend->WSPSend->NtDeviceIoControlFile->AFDSend【Tdi Client】->TcpSendData【Tdi Server】->TdiSend->TcpSend->IPTransmit【Network Layer】->SendIPPacket->下面進(jìn)入鏈路層,沒有找到相關(guān)源碼


NtDeviceIoControlFile:

將發(fā)送請(qǐng)求和完成例程被包裝成IRP,發(fā)送給
"device/afd"

AFDSend:
根據(jù)buffer數(shù)組生成MDL鏈

如果TDI不支持?jǐn)?shù)據(jù)緩沖,這里要將數(shù)據(jù)緩沖下來

調(diào)用TdiBuildSend構(gòu)造發(fā)送到tdi的發(fā)送請(qǐng)求
IRP
將生成新的IRP發(fā)送到
“device/tcp”
AFDSend要么將完整數(shù)據(jù)提交到Tdi,要么失敗,這里不會(huì)導(dǎo)致發(fā)送部分?jǐn)?shù)據(jù)


TcpSendData:
構(gòu)造TdiRequest并調(diào)用TdiSend處理,沒有數(shù)據(jù)緩沖


TdiSend:

構(gòu)造TcpRequest,并將該Request掛入TCB(TCP的傳輸控制塊)的發(fā)送隊(duì)列

調(diào)用TCPSend進(jìn)一步處理

返回
TDI_PENDING
該部分也不會(huì)導(dǎo)致數(shù)據(jù)不完整發(fā)送。


TCPSend:
檢查TCB中發(fā)送隊(duì)列的情況,決定是否啟動(dòng)一次發(fā)送,如果不滿足發(fā)送條件,就返回了

如果符合發(fā)送條件,就構(gòu)造TCP數(shù)據(jù)包,發(fā)送數(shù)據(jù),這個(gè)過程比較復(fù)雜,多為TCP協(xié)議的細(xì)節(jié)處理

可以看出,WSASend一般到TCPSend的開始部分就返回了,TCPSend本身無返回值,是由TdiSend調(diào)用完后就直接返回了Pending。


從源代碼上看,除了發(fā)送的數(shù)據(jù)的字節(jié)為0,否則WSASend是不會(huì)返回STATUS_SUCCESS,不出錯(cuò)的話,一定是返回Pending狀態(tài)


但是應(yīng)用層何時(shí)收到發(fā)送成功通知呢?

我們知道,完成例程指針被存在了最上層的那個(gè)Irp里了,在執(zhí)行IoCompleteRequest的時(shí)候,完成例程會(huì)被調(diào)用,細(xì)節(jié)就不說了,檢索源代碼,有兩個(gè)地方會(huì)導(dǎo)致IoCompleteRequest被最終調(diào)用,一個(gè)是鏈路層調(diào)用IP層的完成例程的時(shí)候,一層層調(diào)用下去,最終導(dǎo)致最上層的那個(gè)IRP的完成例程被調(diào)用,另一個(gè)是再處理TcpReceive的ACK的時(shí)候,也有可能完成掉一些發(fā)送請(qǐng)求。


結(jié)論:

縱觀NT4源代碼,沒有發(fā)現(xiàn)WSASend發(fā)送部分?jǐn)?shù)據(jù)的可能(也許有,我沒看出來)

基于WSASend不會(huì)發(fā)送部分?jǐn)?shù)據(jù),WSASend的確可以重疊發(fā)送(按照投遞順序?qū)l(fā)送請(qǐng)求掛入TCB的發(fā)送隊(duì)列),不必串行,在一定程度上的確能夠提高效率。

所謂發(fā)送完成,應(yīng)該是鏈路層調(diào)用了上層的完成例程,但是鏈路層何時(shí)調(diào)用上層的完成例程,由于源代碼缺乏,不得而知,請(qǐng)知情者賜教!

--------------------------------------------------------------------------------------

 

看來WSASend是在把請(qǐng)求放入TCB隊(duì)列就返回了。Google過一些英文網(wǎng)站,得到類似的回答

 Actually, a partial overlapped send guarantees all subsequently
  scheduled sends will completely fail (assuming a TCP socket).
  A partial overlapped send will never happen in practice, however,
  due to the implementation of the socket buffer (partial sends don't
  exist in Microsoft's WinSock implementations so far). There's an
  exception if you set the send buffer size to zero - then your overlapped
  buffers replace the socket buffer and the socket may break part way
  through an overlapped buffer.

  貌似連續(xù)wsaSend是可行的。

  再看MSDN 有這樣一段話

 For non-overlapped sockets, the last two parameters (lpOverlapped,lpCompletionRoutine) are ignored and WSASend adopts the same blocking semantics assend. Data is copied from the buffer(s) into the transport's buffer. If the socket is non-blocking and stream-oriented, and there is not sufficient space in the transport's buffer,WSASend will return with only part of the application's buffers having been consumed. Given the same buffer situation and a blocking socket,WSASend will block until all of the application buffer contents have been consumed.

     之前的理解有誤,這段話應(yīng)該聯(lián)合起來理解,對(duì)于未使用overlapped的socket,最后兩個(gè)參數(shù)是被忽略的 這時(shí)候wsasend表現(xiàn)就和send一樣,數(shù)據(jù)被拷貝到發(fā)送緩沖區(qū),在這種情況下(wsasend像send) 如果是面向流的nonblockingmodel的套接字  并且發(fā)送緩沖區(qū)不足的情況下,wsasend返回拷貝到發(fā)送緩沖區(qū)的字節(jié)數(shù),如果是blocking socket wsasend知道發(fā)送完畢才返回。(這個(gè)行為和send是一致的,也就是只有在這種情況下wsaSend才會(huì)部分發(fā)送)

  

   什么是non-overlapped sockets?之前一直把non-overlapped sockets 當(dāng)做blocking socket .

   再看windows網(wǎng)絡(luò)編程

   Blocking sockets cause concern because any Winsock API call on a blocking socket can do just that—block for some period of time. Most Winsock applications follow a producer-consumer model in which the application reads (or writes) a specified number of bytes and performs some computation on that data.

   Once a socket is placed in non-blocking mode, Winsock API calls that deal with sending and receiving data or connection management return immediately. In most cases, these calls fail with the error WSAEWOULDBLOCK, which means that the requested operation did not have time to complete during the call. For example, a call torecv returns WSAEWOULDBLOCK if no data is pending in the system's input buffer. Often additional calls to the same function are required until it encounters a successful return code

   No –Blocking socket是不同于non-overlapped socket

      之前對(duì)于overlap的理解還是有些誤區(qū)

現(xiàn)在的理解是 overlap是一種異步使用方式 與block no blocking 不是一個(gè)感念。

 overlapIO不只是socket,還包括readfile等等同樣iocp對(duì)應(yīng)的也不只nonblockingsocket而是 overlapIO

Overlapped sockets merely means that you can use the sockets for overlapped IO. It doesn't mean that your socket is non-blocking.

     完成端口和重疊IO的例子都沒有指定socket必須是non-blocking socket.

non-blocking socket 是指不滿足當(dāng)前條件的情況下     返回,當(dāng)滿足當(dāng)前需求,還是操作完成才返回,例如將發(fā)送緩沖區(qū)填滿。

而overlap socket是只要當(dāng)前情況不能立即執(zhí)行完畢 便會(huì)返回pending 也就是說 在發(fā)送緩沖區(qū)填滿前就已經(jīng)返回了。

 

在我自己的測(cè)試程序中 我把發(fā)送和接受緩沖區(qū)大小都設(shè)置為了0 所以每次發(fā)送返回都是peding,系統(tǒng)鎖定發(fā)送緩沖,當(dāng)發(fā)送完成后得到完成通知。

 

      所以重疊IO和完成IO 與block socket non blocking socket 是兩碼事 ,我接下來測(cè)試下用blocksocket 與non blockingsocket 在iocp上有什么影響 ,個(gè)人現(xiàn)在感覺應(yīng)該是一樣的。(經(jīng)過測(cè)試 用blocking socket iocp仍可正常工作,單non-overlapped socket不行 默認(rèn)的socket()創(chuàng)建出的是支持overlapped的)

      現(xiàn)在的系統(tǒng)使用non-blocking socket必須使用overlap模式

 

     沒想到這篇文章寫了一年之后才來更新 呵呵  寫的比較亂 原諒

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    年轻女房东2中文字幕| 国产精品刮毛视频不卡| 伊人久久五月天综合网| 极品熟女一区二区三区| 中文字幕五月婷婷免费| 国产精品免费视频专区| 亚洲妇女作爱一区二区三区| 国产一区二区不卡在线播放| 国产超碰在线观看免费| 成年人视频日本大香蕉久久| 加勒比日本欧美在线观看| 欧美整片精品日韩综合| 日韩在线精品视频观看| 视频一区二区 国产精品| 热情的邻居在线中文字幕| 五月天综合网五月天综合网| 亚洲人午夜精品射精日韩| 情一色一区二区三区四| 91人妻人人澡人人人人精品| 国产日韩精品欧美综合区| 亚洲精品国男人在线视频| 中文文精品字幕一区二区| 日韩一区二区免费在线观看| 国产又粗又猛又长又黄视频| 日韩欧美国产亚洲一区| 情一色一区二区三区四| 精品伊人久久大香线蕉综合| 不卡免费成人日韩精品| 国产男女激情在线视频| 高跟丝袜av在线一区二区三区| 国产成人午夜在线视频| 五月婷婷六月丁香亚洲| 国产精品伦一区二区三区在线| 亚洲一区二区三区在线中文字幕 | 亚洲天堂精品一区二区| 九九热九九热九九热九九热| 日韩成人动作片在线观看| 太香蕉久久国产精品视频| 国产老女人性生活视频| 九九热国产这里只有精品| 亚洲中文字幕免费人妻|