1. 程式人生 > >非同步SOCKET程式設計-傳送和接收資料

非同步SOCKET程式設計-傳送和接收資料

我本想把傳送和接收分開作為兩部分,但是最後我決定只略微解釋一下 FD_READ ,留下更多的時間來說明更復雜的 FD_WRITE , FD_READ 事件非常容易掌握. 當有資料傳送過來時, WinSock 會以 FD_READ 事件通知你, 對於每一個 FD_READ 事件, 你需要像下面這樣呼叫 recv() :

int bytes_recv = recv(wParam, &data, sizeof(data), 0);

基本上就是這樣, 別忘了修改上面的 wParam. 還有, 不一定每一次呼叫 recv() 都會接收到一個完整的資料包, 因為資料可能不會一次性全部發送過來. 所以在開始處理接收到的資料之前, 最好對接收到的位元組數 ( 即 recv() 的返回值) 進行判斷, 看看是否收到的是一個完整的資料包.

FD_WRITE 相對來說就麻煩一些. 首先, 當你建立了一個連線時, 會產生一個 FD_WRITE 事件. 但是如果你認為在收到 FD_WRITE 時呼叫 send() 就萬事大吉, 那就錯了. FD_WRITE 事件只在傳送緩衝區有多出的空位, 可以容納需要傳送的資料時才會觸發.

上面所謂的傳送緩衝區,是指系統底層提供的緩衝區. send() 先將資料寫入到傳送緩衝區中, 然後通過網路傳送到接收端. 你或許會想, 只要不把傳送緩衝區填滿, 讓傳送緩衝區保持足夠多的空位容納需要傳送的資料, 那麼你就會源源不斷地收到 FD_WRITE 事件了. 嘿嘿, 錯了.上面只是說 FD_WRITE 事件在傳送緩衝區有多出的空位時會觸發, 但不是在有足夠的空位時觸發, 就是說你得先把傳送緩衝區填滿.

通常的辦法是在一個無限迴圈中不斷的傳送資料, 直到把傳送緩衝區填滿. 當傳送緩衝區被填滿後, send() 將會返回 SOCKET_ERROR , WSAGetLastError() 會返回 WSAWOULDBLOCK . 如果當前這個 SOCKET 處於阻塞(同步)模式, 程式會一直等待直到傳送緩衝區空出位置然後傳送資料; 如果SOCKET是非阻塞(非同步)的,那麼你就會得到 WSAWOULDBLOCK 錯誤. 於是只要我們首先迴圈呼叫 send() 直到傳送緩衝區被填滿, 然後當緩衝區空出位置來的時候, 系統就會發出FD_WRITE事件. 有沒有想過我能指出這一點來是多麼不容易, 你可真走運. 下面是一個處理 FD_WRITE 事件的例子.

case FD_WRITE:  // 可以傳送資料了
  {
    // 進入無限迴圈
    while(TRUE)
    {
      // 從檔案中讀取資料, 儲存到 packet.data 裡面.
      in.read((char*)&packet.data, MAX_PACKET_SIZE);

      // 傳送資料
      if (send(wparam, (char*)(&packet), sizeof(PACKET), 0) == SOCKET_ERROR)
      {
        if (WSAGetLastError() == WSAEWOULDBLOCK)
        {
          // 傳送緩衝區已經滿了, 退出迴圈.
          break;
        }
        else // 其他錯誤
        {
          // 顯示出錯資訊然後退出.
          CleanUp();
          return(0);
        }
      }
    }
  } break;

看到了吧, 實現其實一點也不困難. 你只是弄混了一些概念而已. 使用這樣的傳送方式, 在傳送緩衝區變滿的時候就可以退出迴圈. 然後, 當緩衝區空出位置來的時候, 系統會觸發另外一個 FD_WRITE 事件, 於是你就可以繼續傳送資料了.

在你開始使用新學到的知識之前, 我還想說明一下 FD_WRITE 事件的使用時機. 如果你不是一次性發送大批量的資料的話, 就別想著使用 FD_WRITE 事件了, 原因很簡單 - 如果你寄期望於在收到 FD_WRITE 事件時傳送資料, 但是卻又不能傳送足夠的資料填滿傳送緩衝區, 那麼你就只能收到連線剛剛建立時觸發的那一次 FD_WRITE - 系統不會觸發更多的 FD_WRITE 了. 所以當你只是傳送儘可能少的資料的時候, 就忘掉 FD_WRITE 機制吧, 在任何你想傳送資料的時候直接呼叫 send() .

結論
這是我寫過的最長的一篇文章. 我也曾試圖儘可能把它寫短一些來吸引你的注意力, 但是有太多的內容要包括. 在剛剛使用非同步 SOCKET 時, 如果你沒有正確地理解它, 真的會把自己搞胡塗. 我希望我的文章教會了你如何使用它們. ___________________________________

這是我在 GOOGLE 上搜到的一篇文章中的一部分. 雖然原作者的部分觀點似乎並不正確, 但是文章寫得很易懂. 其實, 如果你想收到 FD_WRITE  事件而你又無法先填滿傳送緩衝區, 可以呼叫 WSAAsyncSelect( ..., FD_WRITE ). 如果當前傳送緩衝區有空位, 系統會馬上給你發 FD_WRITE 事件.

FD_WRITE 訊息, MFC 的 CAsyncSocket 類將其對映為 OnSend() 函式. FD_READ 訊息, 被對映為 OnReceive() 函式.

相關推薦

非同步SOCKET程式設計-傳送接收資料

我本想把傳送和接收分開作為兩部分,但是最後我決定只略微解釋一下 FD_READ ,留下更多的時間來說明更復雜的 FD_WRITE , FD_READ 事件非常容易掌握. 當有資料傳送過來時, WinSock 會以 FD_READ 事件通知你, 對於每一個 FD_READ 事件

非同步SOCKET程式設計-傳送接收資料[轉] 非同步SOCKET程式設計-傳送接收資料[轉]

Socket(套接字)◆先看定義: typedef unsigned int u_int; typedef u_int SOCKET; ◆Socket相當於進行網路通訊兩端的插座,只要對方的Socket和自己的Socket有通訊聯接,雙方就可以傳送和接收資料了。其定義類似於檔案控制代碼的定義。◆Socket有

【Java TCP/IP Socket程式設計】----傳送接收資料----構建解析協議訊息

--------筆記來自於書籍《Java TCP/IP Socket程式設計》。 簡介 使用套接字時,通常要麼是需要同時建立通訊通道兩端的程式,要麼實現一個給定的協議進行通訊。如果知道通訊雙方都使用java實現,且擁有對協議的完全控制權,那麼就可以使用Java的內建工具如Serialiabl

【Java TCP/IP Socket程式設計】----傳送接收資料----訊息成幀與解析

目錄   簡介 成幀與解析 成幀技術案例 簡介 在程式中使用套接字向其他程式提供資訊或者使用其他程式提供的資訊,這就需要任何需要交換資訊的程式間在資訊編碼方式上達成共識(包含了資訊交換的形式和意義),稱為協議,用來實現特定的應用程式的協議叫應用程式協議。大部分應

26 API-網路程式設計(網路概述,Socket通訊機制,UDP協議傳送接收資料,TCP協議傳送接收資料)

1:網路程式設計(理解) (1)網路程式設計:用Java語言實現計算機間資料的資訊傳遞和資源共享(2)網路程式設計模型 l網路模型一般是指 OSI(Open System Interconnection開放系統互連)參考模型 TCP/IP參考模型 (3)網路程式

java socket連線以及傳送接收資料

/** * */ package socketTest2; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; import

android連線SSM傳送接收資料

//註冊賬戶 URL url=null; HttpURLConnection httpURLConnection=null; String result=null,re="";

UDP網路程式傳送接收資料

建立一個基於udp的網路程式流程很簡單,具體步驟如下: 1.建立客戶端套接字 2.傳送/接收資料 3.關閉套接字 UDP傳送和接收資料 在 Python 中 使用socket 模組的函式 socket 就可以完成: import socket #

linux多執行緒下開啟串列埠傳送接收資料

1 啟動執行緒1讀串列埠 2 等待3秒後 3 啟動執行緒2寫串列埠,傳送字串後關閉 4 等待10秒 5 關閉兩個執行緒 #include <pthread.h> #include <stdio.h> #include <sys/time.h> #include &

Java實現RS485串列埠通訊,傳送接收資料進行解析

  最近專案有一個空氣檢測儀,需要得到空氣檢測儀的實時資料,儲存到資料庫當中。根據瞭解得到,硬體是通過rs485進行串列埠通訊的,需要傳送16進制命令給儀器,然後通過輪詢來得到資料。   需要先要下載RXTX的jar包,win64位下載地址:http://pan.baidu.com/s/1o6zLmTc);

Java socket模擬傳送接收HTTP訊息

理解:模擬登陸指定網站,登陸成功後,獲取返回串中的cookie值用於發起下次請求。 package demo.http.client; import java.io.IOException; import java.io.InputStream; import java.

通過UDP傳送接收資料

傳送端: package net.udp; import java.io.IOException; import java.net.DatagramPacket; import java.net.Da

網絡卡如何傳送接收資料

 IP報文可以看作一個包。     Linux網絡卡驅動程式,將IP包新增14位元組的MAC包頭,構成MAC包。     MAC包中含有傳送端和接收端的MAC地址資訊。既然是驅動程式建立的MAC包頭資訊,當然可以隨便輸入地址資訊的,主機偽裝就是這麼實現的。    

WebSocket:建立例項、傳送接收資料

1、Web Sockets:能夠在客戶端和服務端之間傳送非常少量的資料,而不必擔心HTTP那樣位元組級的開銷 由於傳遞的資料包很小,因此WebSockets非常適合移動應用。 缺點:制定協議的時間比制定

Vue--axios:vue中的ajax非同步請求(傳送請求資料)、vue-resource非同步請求跨域

跨域原理:一.使用axios傳送get請求 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="

通過python下的socket實現組播資料傳送接收

關於網路組播的解釋我不在此詳述了,想了解的直接百娘就可以了,本人也是新手,研究了幾天Python的組播程式設計後,目前終於成功的解決了自己找的各種麻煩,所以現在總結如下: python實現socket組播有N種寫法,我現在只給出自己認為比較妥當的寫法。 資料傳送 sende

robotframework 學習(2) :使用RIDE進行介面測試之傳送請求接收資料斷言

一、RIDE的介紹:         RIDE是robotframework圖形操作前端,也可以理解為一種編輯器,它以cell的形式來進行定義資料和方法,返回結果等,我們可以使用它進行建立測試用例和編寫測試指令碼,並且執行自動化測試。  

zigbee 之ZStack-2.5.1a原始碼分析(三)無線資料傳送接收

前面說過SampleApp_Init和SampleApp_ProcessEvent是我們重點關注的函式,接下來分析無線傳送和接收相關的程式碼: 在SampleApp_ProcessEvent函式中: if ( events & SYS_EVENT_MSG ) {  &nbs

MQTT Java客戶端Eclipse paho實現資料傳送接收

MQTT(MQ Telemetry Transport)是IBM開發的一種網路應用層的協議 使用場景: 1、不可靠、網路頻寬小的網路 2、執行的裝置CPU、記憶體非常有限 特點: 1、基於釋出/訂閱模型的協議 2、他是二進位制協議,二進位制的特點就是緊湊、佔用

js傳送接收二進位制位元組流資料

傳送二進位制資料 var oReq = new XMLHttpRequest(); oReq.open("POST", url, true); oReq.onload = function (oEvent) { // Uploaded. }; var blo