用readn與written實現解決粘包問題

2021-06-22 00:12:06 字數 2964 閱讀 6697

使用tcp流式套接字,tcp粘包是指傳送方傳送的若干包資料到接收方接

收時粘成一包,從接收緩衝區看,後一包資料的頭緊接著前一包資料的尾。  

出現粘包現象的原因是多方面的,它既可能由傳送方造成,也可能由接

收方造成。傳送方引起的粘包是由tcp協議本身造成的,tcp為提高傳輸效率,

傳送方往往要收集到足夠多的資料後才傳送一包資料。若連續幾次傳送的數

據都很少,通常tcp會根據優化演算法把這些資料合成一包後一次傳送出去,

這樣接收方就收到了粘包資料。出現這種情況的原因是tcp協議採用了著名

的nagle演算法,這種演算法的策略就是把盡量把小的資料報拼接起來傳送,目的

是減少傳送方的系統開銷。

接收方引起的粘包是由於接收方使用者程序不及時接收資料,從而導致粘

包現象。這是因為接收方先把收到的資料放在系統接收緩衝區,使用者程序從

該緩衝區取資料,若下一包資料到達時前一包資料尚未被使用者程序取走,則

下一包資料放到系統接收緩衝區時就接到前一包資料之後,而使用者程序根據

預先設定的緩衝區大小從系統接收緩衝區取資料,這樣就一次取到了多包數

據。 如果網路速率較快的話,建議作乙個高效的協議,從接收端把資料劃分

開來,這是比較普遍的做法。但是如果網路本身較慢,可以關閉nagle演算法。

關於協議的問題以後再討論,這裡介紹關閉nagle演算法的方法:

socket sock;

const int bnodelay = 1;

sock = socket(af_inet,sock_stream,ipproto_tcp);

setsockopt(sock ,ipproto_tcp,tcp_nodelay,(char *)&bnodelay,sizeof(bnodelay));

echocli.c

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define err_exit(m) \

do \

while(0)

struct packet

;ssize_t readn(int fd, void *buf, size_t count)

else if (nread == 0)

return count - nleft;

bufp += nread;

nleft -= nread;

}return count;

}ssize_t writen(int fd, const void *buf, size_t count)

else if (nwritten == 0)

continue;

bufp += nwritten;

nleft -= nwritten;

}return count;

}int main(void)

n = ntohl(recvbuf.len);

ret = readn(sock, recvbuf.buf, n);

if (ret == -1)

err_exit("read");

else if (ret < n)

fputs(recvbuf.buf, stdout);

memset(&sendbuf, 0, sizeof(sendbuf));

memset(&recvbuf, 0, sizeof(recvbuf));

}close(sock);

return 0;

}echosrv.c

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define err_exit(m) \

do \

while(0)

struct packet

;ssize_t readn(int fd, void *buf, size_t count)

else if (nread == 0)

return count - nleft;

bufp += nread;

nleft -= nread;

}return count;

}ssize_t writen(int fd, const void *buf, size_t count)

else if (nwritten == 0)

continue;

bufp += nwritten;

nleft -= nwritten;

}return count;

}void do_service(int conn)

n = ntohl(recvbuf.len);

ret = readn(conn, recvbuf.buf, n);

if (ret == -1)

err_exit("read");

else if (ret < n)

fputs(recvbuf.buf, stdout);

writen(conn, &recvbuf, 4+n);}}

int main(void)

else

close(conn);

}return 0;

}makefile:

.phony:clean all

cc=gcc

cflags=-wall -g

bin=echosrv echocli

all:$(bin)

%.o:%.c

$(cc) $(cflags) -c $< -o $@

clean:

rm -f *.o $(bin)

用AddView和DeleteView實現多視

下面是關於cdocument addview和cdocument removeview的簡單介紹,具體請參見聯機文件 void cdocument addview cview pview 為當前cdocument類例項加入新的檢視。其中引數pview是指向新檢視的指標。void cdocument ...

android AsyncTask 請求與實現

asynctask是對thread和handler進行了封裝,這個封裝的讓我們在進行耗時的操作的時候不用自己啟動執行緒,可以在其類中進行相應的ui更新,這樣大大節約了時間,public class myasynctask extends asynctask 這種使用類泛型的方式進行內部資料的約定,在...

OpenRest nginx lua安裝與例項

1 安裝依賴 make install3 安裝lua依賴 apt get install m4 tar vxzf nettle 3.3.tar.gz cd nettle 3.3 configure make make install4 安裝lua及lua socket tar vxzf lua 5....