導航:首頁 > 操作系統 > linuxconnect非阻塞

linuxconnect非阻塞

發布時間:2022-06-07 07:49:16

❶ 如何判斷非阻塞套接字連接成功

我也來抽個熱鬧,很久沒有見到NIO問題。這位同學,你在生成NIO客戶端連接的時候 有一個參數是「是否同步連接」,你可以借這個來確認連接成功。其次,否則,你就只有像剛才那位老兄說的那樣select or selectNow 來了解 連接狀況。記得,當select or selectNow 之後有個判斷連接是否有效的方法 你可以找下,它應該很有用,希望能夠幫助到你。
是否可以解決您的問題?

❷ 設置非阻塞 要在connect之前嗎

1_set = TIME_OUT_TIME; tm.tv_uset = 0; FD_ZERO(&set); FD_SET(sockfd, &set); if( select(sockfd+1, NULL, &set, NULL, &tm) > 0) { getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len); if(error == 0) ret = true; else ret = false; } else ret = false; } else ret = true; ul = 0; ioctl(sockfd, FIONBIO, &ul); //設置為阻塞模式 if(!ret) { close( sockfd ); fprintf(stderr , "Cannot Connect the server!n"); return; } fprintf( stderr , "Connected!n"); //下面還可以進行發包收包操作 …………… } 以上代碼片段,僅供參考,也是為初學者提供一些提示,主要用到的幾個函數,select, ioctl, getsockopt都可以找到相關資料,具體用法我這里就不贅述了,你只需要在linux中輕輕的敲一個man <函數名>就能夠看到它的用法。 此外我需要說明的幾點是,雖然我們用ioctl把套介面設置為非阻塞模式,不過select本身是阻塞的,阻塞的時間就是其超時的時間由調用select 的 時候的最後一個參數timeval類型的變數指針指向的timeval結構變數來決定的,timeval結構由一個表示秒數的和一個表示微秒數(long 類型)的成員組成,一般我們設置了秒數就行了,把微妙數設為0(註:1秒等於100萬微秒)。而select函數另一個值得一提的參數就是上面我們用到的 fd_set類型的變數指針。調用之前,這個變數裡面存了要用select來檢查的描述符,調用之後,針對上面的程序這裡面是可寫的描述符,我們可以用宏 FD_ISSET來檢查某個描述符是否在其中。由於我這里只有一個套介面描述符,我就沒有使用FD_ISSET宏來檢查調用select之後這個 sockfd是否在set裡面,其實是需要加上這個判斷的。不過我用了getsockopt來檢查,這樣才可以判斷出這個套介面是否是真的連接上了,因為 我們只是變相的用select來檢查它是否連接上了,實際上select檢查的是它是否可寫,而對於可寫,是針對以下三種條件任一條件滿足時都表示可寫 的: 1)套介面發送緩沖區中的可用控制項位元組數大於等於套介面發送緩沖區低潮限度的當前值,且或者i)套介面已連接,或者ii)套介面不要求連接(UDP方式的) 2)連接的寫這一半關閉。 3)有一個套介面錯誤待處理。 這樣,我們就需要用getsockopt函數來獲取套介面目前的一些信息來判斷是否真的是連接上了,沒有連接上的時候還能給出發生了什麼錯誤,當然我程序中並沒有標出那麼多狀態,只是簡單的表示可連接/不可連接。 下面我來談談對這個程序測試的結果。我針對3種情形做了測試: 1. 目標機器網路正常的情況 可以連接到目標主機,並能成功以阻塞方式進行發包收包作業。 2. 目標機器網路斷開的情況 在等待設置的超時時間(上面的程序中為20秒)後,顯示目標主機不能連接。 3. 程序運行前斷開目標機器網路,超時時間內,恢復目標機器的網路 在恢復目標主機網路連接之前,程序一隻等待,恢復目標主機後,程序顯示連接目標主機成功,並能成功以阻塞方式進行發包收包作業。 以 上各種情況的測試結果表明,這種設置connect超時的方法是完全可行的。我自己是把這種設置了超時的connect封裝到了自己的類庫,用在一套監控 系統中,到目前為止,運行還算正常。這種編程實現的connect超時比起修改系統參數的那種方法的有點就在於它只用於你的程序之中而不影響系統。 connect非阻塞套介面時候,一般使用在以下幾種情況: 1.三路握手需要時間,這個要視具體的網路情況而定。當然也有可能失敗。在三路握手的時候我們並不需要在原地等待三路握手的完成,可以用這些時間來 完成其它事情,然後當這些事情完成後,再去檢測連接是否建立(也就是三路握手是否完成)。 2.可以用這種技術來同時建立多個連接。(WEB瀏覽器中很常用)。 3.connect超時需要很長時間才會通知,如果我們認為超過0.1秒以後就算超時(不管它是不是真的超時),這是就可以使用非阻塞式I/O結合 select來完成。 當採用非阻塞式I/O來使用connect時候,要判斷一個連接是否建立則比較復雜,需要按照以下幾個步驟來完成 1.即使是使用非阻塞式的connect操作,connect依然可能正確返回,也就是說非阻塞的connect 也有可能三路連接完成後返回,這種情況一般發生在伺服器和主機在同一個機器上,所以第一步要判斷connect是否正確返回,如果正確返回則請做正確返回 的處理,否則進入步驟2 2.設置fd_set,(如果沒看明白,請先看select函數介紹),讓select函數同時監聽套接字的讀寫2個屬性,如果既可讀也可寫則進入 步驟3,如果可寫但不可讀進入步驟4. 3.如果到達這步,我們需要調用getsockopt進一步判斷。這里涉及到一個移植問題,getsockopt如果發生錯誤, 源自Berkeley的實現會返回0,如果是solaris,則會返回-1。建議是2個都處理(如果看不明白請先看getsockopt函數,套介面選 項)。根據getsockopt通過參數返回的erron的值,如果值為0則表示鏈接建立完成,如果不為0, 則說明鏈接建立沒有完成。 4.如果能到達這里,則說明連接建立完成。 最後,即使最後你得出鏈接沒有建立完成,也只是說:可能三路握手的過程還是沒有完成。 代碼: 伺服器 #include "/programe/net/head.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #define MAXSIZE 100 //如果這樣寫,最後返回的套介面應該是會進入步驟3,也就是套介面既可讀也可寫,如果想進入步驟4,就不要想套介面中寫入數據 int main(int argc, char ** argu) { int listenfd, connfd; struct sockaddr_in servaddr; char buf[MAXSIZE + 1]; char buf2[] = "hello world\n"; listenfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(atoi(argu[1])); bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); listen(listenfd, 10); for(;;) { connfd = accept(listenfd, (struct sockaddr *)NULL, NULL); write(connfd, buf2, sizeof(buf2)); close(connfd); } } 客戶端 #include "/programe/net/head.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "unistd.h" #include "fcntl.h" #include "sys/select.h" #define MAXSIZE 100 int main(int argc, char ** argv) { int sockfd, n; int my; char send_buf[MAXSIZE + 1]; char recv_buf[MAXSIZE + 1]; struct sockaddr_in servaddr; int error = 0; if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf("create socket error\n"); exit(1); } bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(atoi(argv[1])); if(inet_pton(AF_INET, "192.168.1.235" , &servaddr.sin_addr) < 0) { printf("inet_pton error\n"); exit(1); } int val = fcntl(sockfd, F_GETFL, 0); fcntl(sockfd, F_SETFL, val O_NONBLOCK); //設置套介面非阻塞 int connect_flag = connect(sockfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in)); sleep(2); //connect會立即返回,不同於之前的要阻塞到鏈接完成才會返回,這里可以做你想在等待連接完成的時間想做的事情,我這里只是讓進程睡眠了一段時間 if(connect_flag >= 0) { printf("connect success\n"); //即使是非阻塞套介面,connect還是有可能正確返回的,這種情況要處理 goto done; //不建議使用goto } fd_set rest, west; FD_ZERO(&rest); FD_ZERO(&west); FD_SET(sockfd, &rest); FD_SET(sockfd, &west); int maxpd = sockfd + 1; int flag = select(maxpd, &rest, &west, NULL, NULL);//監聽套接的可讀和可寫條件 if(flag < 0) { printf("select error\n");//慢系統調用可能會錯誤返回,這個以前提過 exit(1); } if(FD_ISSET(sockfd, &rest) && FD_ISSET(sockfd, &west)) {//如果套介面及可寫也可讀,需要進一步判斷 socklen_t len = sizeof(error); if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) exit(1);//獲取SO_ERROR屬性選項,當然getsockopt也有可能錯誤返回 printf("error = %d\n", error); if(error != 0) {//如果error不為0, 則表示鏈接到此沒有建立完成 printf("connect failed\n"); exit(1); } //如果error為0,則說明鏈接建立完成 } if(FD_ISSET(sockfd, &west) && !FD_ISSET(sockfd, &rest)) { //如果套介面可寫不可讀,則鏈接完成 printf("connect success\n"); } done: int recv_buf_len = read(sockfd, recv_buf, MAXSIZE); recv_buf[recv_buf_len] = '\0'; printf("get message:%s", recv_buf); close(sockfd); exit(0);

閱讀全文

與linuxconnect非阻塞相關的資料

熱點內容
python正則表達式貪婪模式 瀏覽:646
愛國精神指的是什麼app 瀏覽:408
壽司解壓系列全集視頻 瀏覽:913
物體三維重建演算法 瀏覽:984
fuli直播app哪個好 瀏覽:918
租辦公室用什麼app 瀏覽:106
醫師定期考核刷題app哪個好 瀏覽:338
導出dmp文件命令 瀏覽:288
手機百度網盤怎麼解壓密碼文件 瀏覽:585
索引重新編譯 瀏覽:606
命令與征服4免cd補丁完美版 瀏覽:428
kotlin編譯為native 瀏覽:142
家用編譯機 瀏覽:550
電子加密貨幣最新政策 瀏覽:382
androidcanvas撤銷 瀏覽:271
安卓手機怎麼把圖標全部下移 瀏覽:187
飢荒被伺服器踢出怎麼進 瀏覽:173
c編譯器哪款好 瀏覽:732
快手寶哥發明什麼app 瀏覽:823
張艷玲編譯 瀏覽:68