新聞中心
在使用Linux下C語(yǔ)言Socket編程時(shí),我們經(jīng)常會(huì)遇到阻塞(Blocking)和非阻塞(Non-blocking)的概念。那么什么是Socket阻塞機(jī)制?為什么會(huì)出現(xiàn)阻塞?如何進(jìn)行處理?

一、什么是Socket阻塞機(jī)制?
在C語(yǔ)言中使用Socket進(jìn)行網(wǎng)絡(luò)編程時(shí),阻塞指的是程序停止或暫停執(zhí)行,直到某個(gè)事件發(fā)生才能繼續(xù)執(zhí)行。阻塞是指在程序讀寫數(shù)據(jù)的過(guò)程中,如果條件不符合通信的要求,程序就會(huì)停止執(zhí)行,直到滿足條件才能繼續(xù)執(zhí)行。這里的“條件”指的是網(wǎng)絡(luò)條件,如網(wǎng)絡(luò)是否暢通、目標(biāo)主機(jī)是否在線、數(shù)據(jù)包是否順利傳輸?shù)取?/p>
Socket阻塞機(jī)制是指在Socket通信過(guò)程中,如果有需要等待的事件,Socket會(huì)暫停進(jìn)程的執(zhí)行,直到事件出現(xiàn)為止。例如,當(dāng)我們執(zhí)行Socket的accept函數(shù)時(shí),如果有客戶端連接請(qǐng)求尚未到達(dá),程序就會(huì)一直處于阻塞狀態(tài),直到有客戶端連接請(qǐng)求到達(dá),程序才會(huì)恢復(fù)運(yùn)行。
二、為什么會(huì)出現(xiàn)阻塞?
1. 服務(wù)器忙碌
當(dāng)服務(wù)器負(fù)載較重時(shí),就容易發(fā)生阻塞。如果某個(gè)服務(wù)器在處理請(qǐng)求的過(guò)程中,任務(wù)量過(guò)大,導(dǎo)致服務(wù)器無(wú)法及時(shí)響應(yīng)請(qǐng)求,那么客戶端就會(huì)被迫等待,直到請(qǐng)求得到響應(yīng)。此時(shí)就會(huì)出現(xiàn)阻塞問(wèn)題。
2. 網(wǎng)絡(luò)狀況不佳
除此以外,在網(wǎng)絡(luò)狀況不佳的情況下,也會(huì)出現(xiàn)阻塞。如果網(wǎng)絡(luò)延遲較高,數(shù)據(jù)包傳輸速度變慢,那么就會(huì)導(dǎo)致Socket通信過(guò)程中出現(xiàn)阻塞。
三、如何進(jìn)行處理?
1. 線程和進(jìn)程
為了避免出現(xiàn)阻塞,我們可以使用多線程或多進(jìn)程來(lái)對(duì)Socket進(jìn)行處理。將阻塞操作放在單獨(dú)的線程或進(jìn)程中,然后使用異步I/O來(lái)等待事件發(fā)生,可以避免整個(gè)程序的阻塞問(wèn)題。
2. 非阻塞Socket
還可以使用非阻塞Socket進(jìn)行處理。非阻塞Socket是指在Socket通信過(guò)程中,程序執(zhí)行不會(huì)被阻塞,而是立即返回。此時(shí),程序可以進(jìn)行其他操作,直到Socket準(zhǔn)備好。當(dāng)Socket準(zhǔn)備好時(shí),程序會(huì)得到一個(gè)通知,然后程序會(huì)立即進(jìn)行讀入或發(fā)送操作,以達(dá)到流暢通信的目的。
3. 設(shè)置超時(shí)
此外,我們還可以在程序中設(shè)置超時(shí)。當(dāng)程序等待數(shù)據(jù)超過(guò)指定時(shí)間時(shí),就會(huì)立即放棄等待,進(jìn)行其他操作。這種方式適用于程序需要在特定時(shí)間內(nèi)響應(yīng)的情況。
:
Socket阻塞機(jī)制是Socket通信過(guò)程中需要等待的事件引發(fā)的進(jìn)程阻塞。在編寫Socket程序時(shí),要考慮網(wǎng)絡(luò)狀況和服務(wù)器負(fù)載等因素,合理選擇處理方法,如使用多線程或多進(jìn)程、使用非阻塞Socket和設(shè)置超時(shí)等。這些處理方式有助于提高程序的并發(fā)度和響應(yīng)速度,使程序在高并發(fā)和大流量情況下也可以保持流暢通信。
相關(guān)問(wèn)題拓展閱讀:
- LINUX C下ACCEPT失敗,前面SOCKET,BIND,LISTEN都成功
- linux下C語(yǔ)言socket編程雙機(jī)互發(fā)數(shù)據(jù)
- Linux下Socket編程 怎樣實(shí)現(xiàn)客戶端之間互相通信
LINUX C下ACCEPT失敗,前面SOCKET,BIND,LISTEN都成功
應(yīng)答是要陵巖使用另外一個(gè)空的socket對(duì)象進(jìn)行應(yīng)尺坦御答。而且這個(gè)socket對(duì)象必須沒(méi)有被賦值。例信升如下面的程序段;
while (AcceptSock == SOCKET_ERROR)
{
AcceptSock = accept(ConnectSocket,NULL,NULL);
}
我建議 閱讀 《unix網(wǎng)絡(luò)編程》里面有很詳細(xì)的解釋
舉個(gè)例子:
你可以把socket的IO操作看做是等人
阻塞:
你站在和人越好的地毀念方等人,你們的約定了一個(gè)時(shí)槐森間,當(dāng)你等的時(shí)間超過(guò)了這個(gè)時(shí)間后你就可以離開這個(gè)地點(diǎn)去干其他的事情,否則你將繼續(xù)在這里等人。而INFINIT就是無(wú)限等待下去
非阻塞:
就是你不需要站在越好的地點(diǎn)等人,你可以作在離這個(gè)地點(diǎn)很近的纖明困一個(gè)咖啡廳喝茶聽音樂(lè),但你能夠看到這個(gè)約定地點(diǎn)的情況,一旦有人來(lái)你就可以走過(guò)去和那個(gè)人見面
阻塞:人來(lái)了以后你可以之一時(shí)間見到,而不用別人等你
非阻塞:和你正在做的事情有關(guān),如果你在坐在咖啡廳看電視,就很有可能造成別人等你的情況了
看看errno,如果是EAGAIN或EWOULDBLOCK是正常的。
你bupt-is的吧?我也遇到這個(gè)問(wèn)題了,換臺(tái)電腦就好了
linux下C語(yǔ)言socket編程雙機(jī)互發(fā)數(shù)據(jù)
這么專業(yè)的問(wèn)題去專業(yè)的網(wǎng)站或搜索QQ群上問(wèn)吧,百度里有空回答的怕沒(méi)幾個(gè)人知道。
這個(gè)問(wèn)題很好辦啦,服務(wù)器接受一個(gè)連接請(qǐng)求,然后開一個(gè)線程或者進(jìn)程都可以,再在線程或者進(jìn)程里面采用其他技術(shù)實(shí)現(xiàn)同時(shí)收發(fā)(比如I/O復(fù)用,比如非阻塞I/O)??蛻舳艘部梢圆捎肐/O復(fù)用。
推薦資含尺攔料的話,《unix網(wǎng)絡(luò)編程》這本書很好,公認(rèn)的經(jīng)典,當(dāng)教科書用,這本書里有你想要的所有內(nèi)容。
ps:你基礎(chǔ)太差,多補(bǔ)補(bǔ)吧,別想一下吃困桐個(gè)胖子。
另外我這里正好有個(gè)例子滿足你的要求,貼給你,自己寫的,不是網(wǎng)上找的,用的是多進(jìn)程加I/O復(fù)用技術(shù):
server端:
/****************************************************************
**
**
**
****************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define BUFLEN 1024
#define MAX(a,b) ((a)>(b)?(a):(b))
typedef void Sigfunc (int);
void str_echo(FILE *,int);
//Sigfunc *signal(int, Sigfunc *);
int main(int argc,char **argv)
{
int connfd,listenfd;
pid_t childpid;
socklen_t clilen;
struct sockaddr_in cliaddr,servaddr;
void sig_chld(int);
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(5358);
bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr));
listen(listenfd,8);
signal(SIGCHLD,sig_chld);
while(1)
{
clilen = sizeof(cliaddr);
if((connfd = accept(listenfd,(struct sockaddr*)&cliaddr,&clilen)) 0)
{
printf(“child %d terminated\n”,pid);
}
return;
}
client端:
#include
#include
#include
#include
#include
#include
#include
#define MAX(a,b) (a)>(b)?(a):(b)
int main()
{
int s,connectReturn, maxfd;
fd_set rset;
char sendbuf = {0};
char recvbuf = {0};
long port=5358;
s=socket(PF_INET,SOCK_STREAM,0);
struct sockaddr_in sa;
sa.sin_family=AF_INET;
sa.sin_addr.s_addr=inet_addr(“127.0.0.1”);
sa.sin_port=htons(port);
connectReturn=connect(s,(struct sockaddr *)&sa,sizeof(sa));
printf(“%d\n”,connectReturn);
FD_ZERO(&rset);
while(1)
{
FD_SET(fileno(stdin), &rset);
FD_SET(s, &rset);
maxfd=MAX(fileno(stdin), s) + 1;
select(maxfd, &rset, NULL, NULL, NULL);
if(FD_ISSET(fileno(stdin), &rset))
{
scanf(“%s”,sendbuf);
send(s,sendbuf,strlen(sendbuf),0);
bzero(sendbuf, 1024);
}
else if(FD_ISSET(s, &rset))
{
memset(recvbuf,0,1024);
recv(s,recvbuf,1024,0);
printf(“remote: %s\n”,recvbuf);
}
}
return 0;
Linux下Socket編程 怎樣實(shí)現(xiàn)客戶端之間互相通信
網(wǎng)絡(luò)的Socket數(shù)據(jù)傳輸是一種特殊的I/O,Socket也是一種文件描述符。Socket也具有一個(gè)類似于打開文件的函數(shù)調(diào)用Socket(),該函數(shù)返回一個(gè)整型的Socket描述符,隨后的連接建立、數(shù)據(jù)傳輸?shù)炔僮鞫际峭ㄟ^(guò)該Socket實(shí)現(xiàn)的。
下面用Socket實(shí)現(xiàn)一個(gè)windows下的c語(yǔ)言socket通信例子,這里我們客戶端傳遞一個(gè)字符串,服務(wù)器端進(jìn)行接收。
【服務(wù)器端】
#include “stdafx.h”
#include
#include
#include
#define SERVER_PORT 5208 //偵聽端口
void main()
{
WORD wVersionRequested;
WSADATA wsaData;
int ret, nLeft, length;
SOCKET sListen, sServer; //偵聽套接字,連接套接字
struct sockaddr_in saServer, saClient; //地址信息
char *ptr;//用于遍歷信息的指針
//WinSock初始化
wVersionRequested=MAKEWORD(2, 2); //希望使用的WinSock DLL 的版本
ret=WSAStartup(wVersionRequested, &wsaData);
if(ret!=0)
{
printf(“WSAStartup() failed!\n”);
return;
}
//創(chuàng)建Socket,使用TCP協(xié)議
sListen=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sListen == INVALID_SOCKET)
{
WSACleanup();
printf(“socket() faild!\n”);
return;
}
//構(gòu)建本地地址信息
saServer.sin_family = AF_INET; //地址家族
saServer.sin_port = htons(SERVER_PORT); //注意轉(zhuǎn)化為網(wǎng)絡(luò)字節(jié)序
saServer.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //使用INADDR_ANY 指示任意地址
//綁定
ret = bind(sListen, (struct sockaddr *)&saServer, sizeof(saServer));
if (ret == SOCKET_ERROR)
{
模核printf(“bind() faild! code:%d\n”, WSAGetLastError());
closesocket(sListen); //關(guān)閉套接字
WSACleanup();
return;
}
//偵聽連接請(qǐng)求
ret = listen(sListen, 5);
if (ret == SOCKET_ERROR)
{
printf(“l(fā)isten() faild! code:%d\n”, WSAGetLastError());
closesocket(sListen); //關(guān)閉套接字
return;
}
printf(“Waiting for client connecting!\n”);
printf(“Tips: Ctrl+c to quit!\n”);
//阻塞等待接受客戶端連接
while(1)//循環(huán)監(jiān)聽客戶端,永遠(yuǎn)不停止,所以,在本項(xiàng)目中,我們沒(méi)有心跳包。
{
length = sizeof(saClient);
散碼喚 sServer = accept(sListen, (struct sockaddr *)&saClient, &length);
if (sServer == INVALID_SOCKET)
{
printf(“accept() faild! code:%d\n”, WSAGetLastError());
closesocket(sListen); //關(guān)閉套接字
WSACleanup();
return;
}
char receiveMessage;
nLeft = sizeof(receiveMessage);
ptr = (char *)&receiveMessage;
while(nLeft>0)
{
//接收數(shù)據(jù)
ret = recv(sServer, ptr, 5000, 0);
if (ret == SOCKET_ERROR)
{
printf(“recv() failed!\n”);
return;
}
if (ret == 0) //客戶端已經(jīng)關(guān)沖凱閉連接
{
printf(“Client has closed the connection\n”);
break;
}
nLeft -= ret;
ptr += ret;
}
printf(“receive message:%s\n”, receiveMessage);//打印我們接收到的消息。
}
// closesocket(sListen);
// closesocket(sServer);
// WSACleanup();
}
【客戶端】
#include “stdafx.h”
#include
#include
#include
#define SERVER_PORT 5208 //偵聽端口
void main()
{
WORD wVersionRequested;
WSADATA wsaData;
int ret;
SOCKET sClient; //連接套接字
struct sockaddr_in saServer; //地址信息
char *ptr;
BOOL fSuccess = TRUE;
//WinSock初始化
wVersionRequested = MAKEWORD(2, 2); //希望使用的WinSock DLL的版本
ret = WSAStartup(wVersionRequested, &wsaData);
if(ret!=0)
{
printf(“WSAStartup() failed!\n”);
return;
}
//確認(rèn)WinSock DLL支持版本2.2
if(LOBYTE(wsaData.wVersion)!=2 || HIBYTE(wsaData.wVersion)!=2)
{
WSACleanup();
printf(“Invalid WinSock version!\n”);
return;
}
//創(chuàng)建Socket,使用TCP協(xié)議
sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sClient == INVALID_SOCKET)
{
WSACleanup();
printf(“socket() failed!\n”);
return;
}
//構(gòu)建服務(wù)器地址信息
saServer.sin_family = AF_INET; //地址家族
saServer.sin_port = htons(SERVER_PORT); //注意轉(zhuǎn)化為網(wǎng)絡(luò)節(jié)序
saServer.sin_addr.S_un.S_addr = inet_addr(“192.168.1.127”);
//連接服務(wù)器
ret = connect(sClient, (struct sockaddr *)&saServer, sizeof(saServer));
if (ret == SOCKET_ERROR)
{
printf(“connect() failed!\n”);
closesocket(sClient); //關(guān)閉套接字
WSACleanup();
return;
}
char sendMessage=”hello this is client message!”;
ret = send (sClient, (char *)&sendMessage, sizeof(sendMessage), 0);
if (ret == SOCKET_ERROR)
{
printf(“send() failed!\n”);
}
else
printf(“client info has been sent!”);
closesocket(sClient); //關(guān)閉套接字
WSACleanup();
}
網(wǎng)絡(luò)的Socket數(shù)據(jù)傳輸是一種特殊的I/O,Socket也是一種文件描述符。Socket也具有一個(gè)類似于打開文件的函數(shù)調(diào)用Socket(),該函數(shù)返回一個(gè)整型的Socket描述符,隨后的連接建立、數(shù)據(jù)傳輸?shù)炔僮鞫际峭ㄟ^(guò)該銀鉛搜Socket實(shí)現(xiàn)的。下面用Socket實(shí)現(xiàn)一個(gè)windows下的c語(yǔ)言socket通信例子,這里我們客戶端傳遞一個(gè)字符串,服務(wù)器端進(jìn)行接收。
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
【服務(wù)鋒歷激嘩器端】
#include “stdafx.h”
#include
#include
#include
#define SERVER_PORT 5208 //偵聽端口
void main()
關(guān)于linux c socket 阻塞的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。
香港服務(wù)器選創(chuàng)新互聯(lián),2H2G首月10元開通。
創(chuàng)新互聯(lián)(www.cdcxhl.com)互聯(lián)網(wǎng)服務(wù)提供商,擁有超過(guò)10年的服務(wù)器租用、服務(wù)器托管、云服務(wù)器、虛擬主機(jī)、網(wǎng)站系統(tǒng)開發(fā)經(jīng)驗(yàn)。專業(yè)提供云主機(jī)、虛擬主機(jī)、域名注冊(cè)、VPS主機(jī)、云服務(wù)器、香港云服務(wù)器、免備案服務(wù)器等。
網(wǎng)站題目:深入理解:Linux下C語(yǔ)言Socket阻塞機(jī)制(linuxcsocket阻塞)
文章起源:http://www.dlmjj.cn/article/codgijh.html


咨詢
建站咨詢
