乙個簡單的tcp非阻塞connect的客戶端

2021-08-19 22:51:46 字數 2975 閱讀 5400

我們知道,tcp客戶端要與服務端通訊,必須先建立連線,即呼叫connect函式完成三次握手,而預設情況下connect是阻塞方式的,也就是說呼叫connect函式會發生阻塞,超時時間可能在75s至幾分鐘之間。當然同一主機除外,同一主機上呼叫connect通常會立即成功。

為避免長時間的connect阻塞,可以使用如下非阻塞connect方式來處理:

一、 建立socket,返回套介面描述符

二、 呼叫fcntl把套介面描述符設定成非阻塞

三、 呼叫connect開始建立連線

四、 判斷連線是否成功建立

a: 如果connect返回0,表示連線成功(伺服器和客戶端在同一臺機器上時就有可能發生這種情況)                

b: 呼叫select來等待連線建立成功完成                                

(berkeley的實現(和posix.1g)有兩條與select和非阻塞io相關的規則: 

1.當連線建立成功時,套介面描述符變成可寫;

2.當連線出錯時,套介面描述符變成既可讀又可寫;

注意:當乙個套介面出錯時,它會被select呼叫標記為既可讀又可寫;)

五、 繼續判斷select返回值

如果select返回0,則表示建立連線超時; 我們返回超時錯誤給使用者,同時關閉連線,以防止三路握手操作繼續進行下去

如果select返回大於0的值,則需要檢查套介面描述符是否可讀或可寫;如果套介面描述符可讀或可寫,則我們可以通過呼叫getsockopt來得到套介面上待處理的錯誤(so_error),如果連線建立成功,這個錯誤值將是0,如果建立連線時遇到錯誤,則這個值是連線錯誤所對應的errno值(比如:econnrefused,etimedout等).

#include #include #include #include #include #include #include #include #include #include #include #include #define dstaddr     "192.168.1.44"

#define dstport 30040

int main(int argc, char* argv)

; struct sockaddr_in servaddr;

socklen_t addr_size = 0;

char destaddr[16] = ;

int destport = 0;

int recv_len = 0;

char who[64] = ;

char sndbuffer[256] = ;

struct timeval tvbegin;

struct timeval tvend;

if(argc < 3)

else

/*---- create socket ----*/

if((sockfd = socket(pf_inet, sock_stream, 0)) < 0)

/*---- set non-block ----*/

int options = fcntl(sockfd, f_getfl, 0);

fcntl(sockfd, f_setfl, options | o_nonblock);

/*---- configure settings of connection ----*/

bzero(&servaddr, sizeof(servaddr));

servaddr.sin_family = af_inet;

servaddr.sin_port = htons(destport);

servaddr.sin_addr.s_addr = inet_addr(destaddr);

/* set padding field to 0 */

//memset(servaddr.sin_zero, 0, sizeof(servaddr.sin_zero));

/*---- connect ----*/

ret = connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

if(ret == 0)

else if(ret < 0)

if (ret == 0)

else

else

if(err != 0)

else}}

}}

/*---- send ----*/

strcpy(sndbuffer,"hello!\r\n");

if((ret = send(sockfd, sndbuffer, strlen(sndbuffer), 0)) > 0)

else

gettimeofday(&tvbegin, null);

while(1)

else

}else if(recv_len == 0)

else

else if(strstr(buffer, "heartbeat"))

usleep(100);

memset(sndbuffer, 0, sizeof(sndbuffer));

sprintf(sndbuffer, "%s request other...\r\n", who);

if((ret = send(sockfd,sndbuffer,strlen(sndbuffer),0)) > 0)}}

//gettimeofday(&tvend, null);

unsigned int subtime = tvend.tv_sec-tvbegin.tv_sec;

//printf(".............%d....\n", subtime);

if(subtime > 3)

}usleep(1000);

}return 0;

}

TCP非阻塞accept和非阻塞connect

非阻塞accept 當乙個已完成的連線準備好被accept的時候,select會把監聽socket標記為可讀。因此,如果用select等待外來的連線時,應該不需要把監聽socket設定為非阻塞模式,因為如果select告訴我們連線已經就緒,accept就不應該被阻塞。不過這樣做的時候有乙個bug 當...

TCP和UDP阻塞和非阻塞之間的區別

首先socket在預設情況下是阻塞狀態的,這就使得傳送以及接收操作處於阻塞的狀態,即呼叫不會立即返回,而是進入睡眠等待操作完成。下面把討論點分為傳送以及接收。一.傳送選用send 這裡特指tcp 以及sendto 這裡特指udp 來描述 首先需要說明的是,不管阻塞還是非阻塞,在傳送時都會將資料從應用...

知乎上乙個關於同步非同步阻塞非阻塞的有趣解釋

老張愛喝茶,廢話不說,煮開水。出場人物 老張,水壺兩把 普通水壺,簡稱水壺 會響的水壺,簡稱響水壺 1 老張把水壺放到火上,立等水開。同步阻塞 老張覺得自己有點傻 2 老張把水壺放到火上,去客廳看電視,時不時去廚房看看水開沒有。同步非阻塞 老張還是覺得自己有點傻,於是變高階了,買了把會響笛的那種水壺...