androidsocket阻塞
1. android的socket怎樣判斷斷線
非阻塞模式,如果暫時沒有數據,返回的值也會是<=0的,如果用阻塞模式的話,返回<=0的值是可以認為socket已經無效了。
當使用 select()函數測試一個socket是否可讀時,如果select()函數返回值為1,
且使用recv()函數讀取的數據長度為0 時,就說明該socket已經斷開。
經過代碼試驗,如果進程受到一些信號時,例如:EINTR,recv()返回值小於等於0時,這是就需要判斷 errno是否等於 EINTR , 如果errno == EINTR 則說明recv函數是由於程序接收到信號後返回的,socket連接還是正常的,不應close掉socket連接。
如果write,我覺得還有一些情況需要考慮,那就是寫的太快的時候,有可能buffer寫滿了,這是,errno是EAGAIN,可以根據實際需要,如果errno是EAGAIN的話,再寫幾次。
當然,read的時候也有類似write的情況,需要check一下errno,如果是EAGAIN或者EINTR,最好不要立刻終止操作,再嘗試一下!
這是我寫的一個代碼!int SocketConnected(int sock)
{
int res,recvlen;
char buf[20] = {'\0'};
struct timeval timeout={3,0};
fd_set rdfs;
FD_ZERO(&rdfs);
FD_SET(sock,&rdfs);
res = select(sock+1,&rdfs,NULL,NULL,&timeout);
if(res > 0){
recvlen = recv(sock,buf,sizeof(buf),0);
if(recvlen > 0){
printf("socket connected\n");
return 1;
} else if (recvlen < 0 ){
if(errno == EINTR){
printf("socket connected\n");
return 1;
}else {
printf("socket disconnected! connect again!\n");
return 0;
}
} else if (recvlen == 0){
printf("socket disconnected!connect again\n");
return 0;
}
} else if(res == 0 ){
//time out
printf("socket connected\n");
return 1;
} else if(res < 0){
if (errno == EINTR){
printf("socket connected\n");
return 1;
}else{
printf("socket disconnected ! connect again!\n");
return 0;
}
}
return 0;
}
2. android socket一直在鏈接 伺服器不響應
connect方法裡面:new Socket那會拋異常的。導致你上部分catch到異常。writer沒有被初始化。 接下來估計你直接使用了writer。導致了空指針異常。 所以關鍵是你的:new Socket這里。這個地方很用可能是服務端沒有打開,而導致的連接異常
3. Android - Socket簡單使用
ServerSocket類提供如下構造器:
當ServerSocket使用完畢,應使用 close() 方法來關閉此ServerSocket。通常情況下,伺服器不應該只接收一個客戶端請求,而應該不斷接收來自客戶端的請求,所以程序可以通過循環,不斷調用ServerSocket的accept方法:
Socket 常用構造器
註:上面兩個構造器指定遠程主機時既可以使用InetAddress來指定,也可以直接使用String對象來指定遠程IP。本地主機只有一個IP地址時,使用第一個方法更簡單。
在與伺服器進行通訊的時候,無法判斷遠程的伺服器是否斷開連接。如果使用 OutputStream 發送數據則會影響正常的數據發送(無法區分)。所以就引入了一個心跳機制。
心跳機制實現,使用 Socket.sendUrgentData() 方法發送一個位元組流數據(緊急數據)。可以通過判斷服務端的 OOBINLINE 屬性是否打開,來確定是否斷開連接;
setSoTimeout()理解 :設置超時時間;例如:設置為2s,如果阻塞的時間>2s ,那麼就會報錯。
4. android 子線程socket.receive(packet)阻塞
退出時,關閉子線程。
5. Android-Socket
由於二者不屬於同一層面,所以本來是沒有可比性的。但隨著發展,默認的Http里封裝了下面幾層的使用,所以才會出現Socket & HTTP協議的對比:(主要是工作方式的不同):
Socket可理解為一種特殊的文件,在伺服器和客戶端各自維護一個文件,並使用SocketAPI函數對其進行文件操作。在建立連接打開後,可以向各自文件寫入內容供對方讀取或讀取對方內容,通信結束時關閉文件。在UNIX哲學中「一切皆文件」,文件的操作模式基本為「打開-讀寫-關閉」三大步驟,Socket其實就是這個模式的一個實現。
創建socket的時候,也可以指定不同的參數創建不同的socket描述符,socket函數的三個參數分別為:
當我們調用socket創建一個socket時,返回的socket描述字它存在於協議族(address family,AF_XXX)空間中,但沒有一個具體的地址。如果想要給它賦值一個地址,就必須調用bind()函數,否則就當調用connect()、listen()時系統會自動隨機分配一個埠。
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
函數的三個參數分別為:
如果作為一個伺服器,在調用socket()、bind()之後就會調用listen()來監聽這個socket,如果客戶端這時調用connect()發出連接請求,伺服器端就會接收到這個請求。
TCP伺服器端依次調用socket()、bind()、listen()之後,就會監聽指定的socket地址了。TCP客戶端依次調用socket()、connect()之後就想TCP伺服器發送了一個連接請求。TCP伺服器監聽到這個請求之後,就會調用accept()函數取接收請求,這樣連接就建立好了。之後就可以開始網路I/O操作了,即類同於普通文件的讀寫I/O操作。
注意:accept的第一個參數為伺服器的socket描述字,是伺服器開始調用socket()函數生成的,稱為監聽socket描述字;而accept函數返回的是已連接的socket描述字。一個伺服器通常通常僅僅只創建一個監聽socket描述字,它在該伺服器的生命周期內一直存在。內核為每個由伺服器進程接受的客戶連接創建了一個已連接socket描述字,當伺服器完成了對某個客戶的服務,相應的已連接socket描述字就被關閉。
萬事具備只欠東風,至此伺服器與客戶已經建立好連接了。可以調用網路I/O進行讀寫操作了,即實現了網咯中不同進程之間的通信!網路I/O操作有下面幾組:
read()/write()
recv()/send()
readv()/writev()
recvmsg()/sendmsg()
recvfrom()/sendto()
我推薦使用recvmsg()/sendmsg()函數,這兩個函數是最通用的I/O函數,實際上可以把上面的其它函數都替換成這兩個函數。
從圖中可以看出,當客戶端調用connect時,觸發了連接請求,向伺服器發送了SYN J包,這時connect進入阻塞狀態;伺服器監聽到連接請求,即收到SYN J包,調用accept函數接收請求向客戶端發送SYN K ,ACK J+1,這時accept進入阻塞狀態;客戶端收到伺服器的SYN K ,ACK J+1之後,這時connect返回,並對SYN K進行確認;伺服器收到ACK K+1時,accept返回,至此三次握手完畢,連接建立。
總結:客戶端的connect在三次握手的第二個次返回,而伺服器端的accept在三次握手的第三次返回。
某個應用進程首先調用close主動關閉連接,這時TCP發送一個FIN M;
另一端接收到FIN M之後,執行被動關閉,對這個FIN進行確認。它的接收也作為文件結束符傳遞給應用進程,因為FIN的接收意味著應用進程在相應的連接上再也接收不到額外數據;
一段時間之後,接收到文件結束符的應用進程調用close關閉它的socket。這導致它的TCP也發送一個FIN N;
接收到這個FIN的源發送端TCP對它進行確認。
這樣每個方向上都有一個FIN和ACK。
所謂短連接,即連接只保持在數據傳輸過程,請求發起,連接建立,數據返回,連接關閉。它適用於一些實時數據請求,配合輪詢來進行新舊數據的更替。
https://github.com/nuisanceless/MySocketDemo
https://github.com/xuuhaoo/OkSocket
6. android藍牙通訊Socket.connect()方法調用不成功。為什麼
UUID值出現錯誤。
看一下android有關bluetooth的API,用於普通藍牙適配器和android手機藍牙模塊連接的,而且這個UUID的值必須是00001101-0000-1000-8000-00805F9B34FB。
這個是android的API上面說明的.connect().在連接的時候,android手機作client(主動和電腦建立連接),如果電腦作為server(一直監聽是否有服務連接),則需要在手機端調用這樣一行代碼.兩邊的UUID必須是一樣的,這是一個服務的唯一標識。