在socket建立時,linux的核心會為socket分配乙個傳送緩衝區和乙個接收緩衝區,實際上是乙個struct sk_buff的佇列,當我們呼叫send/sendto/sendmsg及recv/recvfrom/recvmsg時,會傳送或接收佇列中的第乙個資料。
現在我們只考慮接收的情況,如果甲一直不停的向乙傳送訊息,而乙中每次呼叫recv/recvfrom/recvmsg都想得到最新的資料,怎麼辦?
這就需要我們對linux的緩衝區進行清空。而緩衝區是在核心中的,不允許直接操作。還好,有兩個函式可以解決這個問題。
第乙個是int setsockopt(int socket, int level, int option_name, const void *option_value, socklen_t option_len), 他是對
socket的設定。我們可以通過它修改接收緩衝區的大小。他還有很多功能,見man setsockopt.
int llen, lret
lret = setsockopt(sock, sol_socket, so_rcvbuf, &llen, sizeof(int));
sock就是我們建立的socket 的描述符。
如果對linux核心**進行研究,會發現llen不是設定成所有的值都有效。
if (val > sysctl_rmem_max)
val = sysctl_rmem_max;
set_rcvbuf:
sk->sk_userlocks |= sock_rcvbuf_lock;
/* fixme: is this lower bound the right one? */
if ((val * 2) < sock_min_rcvbuf)
sk->sk_rcvbuf = sock_min_rcvbuf;
else
sk->sk_rcvbuf = val * 2;
break;
也就說,他有乙個最大值和乙個最小值。 最大值是262144, 最小值是256。
我們在看一下核心中緩衝區分配的函式
...size = skb_data_align(size);
...skb->truesize = size + sizeof(struct sk_buff);
在sock_queue_rcv_skb函式中有
if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
(unsigned)sk->sk_rcvbuf)
這樣,當接收到乙個資料報後,核心緩衝區會分配size + sizeof(struct sk_buff)大小的緩衝區,其中size是cache line對齊的。
也就是說,只有我們設定的緩衝區大於這個值,資料才會到使用者空間。
好了,我們設定了接收區的大小以後,緩衝區中只有乙個資料報,可以用select函式進行清空。
struct timeval stwait;
fd_set stfdset;
int lret;
stwait.tv_sec = 0;
stwait.tv_usec = 0;
while(1)
然後再呼叫recvfrom接收最新的訊息。
Linux下如何清空socket的接收緩衝區的資料
最近碰到乙個問題,對於阻塞模式的socket通訊,如果要實現裝置的命令控制,那麼進入命令流前,緩衝區不能存有上次通訊沒有取回的資訊,否則一旦命令發出,然後讀取緩衝區,很顯然會讀到上一次的剩餘資料。做法當然很簡單,就是先清除接收區的緩衝資料,可是如何清除?網上有很多這樣的問題,但都沒什麼規範的解決辦法...
socket接收訊息
標頭檔案在主頁 編譯方式 gcc server.c o server執行方式 server 埠號程式主體 int main int argc,char ar server 埠 建立udp套接字 fd socket af inet,sock dgram,0 準備跟af inet 即ipv4網路層協議 ...
celery清空佇列
本人在使用python celery佇列時,有時候需要清空佇列,但是python celery似乎並沒有清空佇列的api 至少我沒找到 所以使用redis cli工具進行佇列清空 使用redis cli工具,命令如下,在終端直接輸入 redis cli n 15 ltrim transcode 0 ...