先上程式碼:
//server
void newConnection(int sockfd,const InetAddress &addr)
{
::write(sockfd, "how are you?\n", 13); //簡單地回復(fù)一句話
}
int main()
{
EventLoop loop;
InetAddress listenAddr(12345);
Acceptor acceptor(&loop, listenAddr);
acceptor.setConnectionCallback(newConnection); //listenfd可讀(新連接)調(diào)用回調(diào)
acceptor.listen(); //Accept::listen調(diào)用listenfd的listen
//while(true)循環(huán),Acceptor構(gòu)造時(shí)講listenfd放進(jìn)loop的epoll結(jié)構(gòu)中,
//本循環(huán)檢測到listenfd可讀(新連接)之后調(diào)用accept得到connfd,然后調(diào)用上面set的回調(diào)函數(shù)
loop.loop();
}
//client
int main(int argc, char **argv)
{
struct sockaddr_in addr;
bzero(&addr, sizeof addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(12345);
inet_pton(AF_INET, argv[1], &addr.sin_addr);
int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); //連接server
char buf[256] = {'rrreee'};
read(sockfd, buf, sizeof(buf)); //接受msg
printf("Received: %s\n", buf);
close(sockfd);
return 0;
}
整個(gè)程式流程大致如下:
server啟動之後Acceptor處於listen狀態(tài),然後client請求連接,連接成功server就呼叫回呼newConnection發(fā)送「how are you」給client,client接受之後才印出來。
下面說下錯(cuò)誤情況:
使用gdb調(diào)試發(fā)現(xiàn)每次在::write(sockfd, "how are you?\n", 13);
就會接收到 SIGPIPE
然後程式死掉。
查了一下Program received signal SIGPIPE, Broken pipe.的原因,都說是對無效(未連接或連接斷開)的sockfd進(jìn)行write。但是我的程式運(yùn)行到回呼函數(shù)的write時(shí)也沒有出現(xiàn)關(guān)閉連接的情況。 (為了調(diào)試我還把所有程式碼中出現(xiàn)的close都註解掉)
另外,gdb調(diào)試到write的時(shí)候,我還用ll /proc/pid/fd
查看了當(dāng)前系統(tǒng)佔(zhàn)用描述符,connfd也還存在著。
所以完全搞不懂為什麼還會有SIGPIPE,求指教!
已解決,原因是::accept的第三個(gè)參數(shù)傳錯(cuò)
我的程式碼中,accept wrapper如下:
Accept(int listenfd, struct sockaddr *addr)
{
socklen_t len = sizeof(*addr);
int connfd = ::accept(listenfd, addr, &len);
//...
}
呼叫程式碼為
struct sockaddr_in addr;
//...
int connfd = Accept(listenfd, &addr);
錯(cuò)誤應(yīng)該是在於::accpet的第三個(gè)參數(shù),傳遞的應(yīng)該是原sockaddr_in的大小而不是轉(zhuǎn)換後的sockaddr的大小。修改如下:
Accept(int listenfd, struct sockaddr_in *addr)
{
socklen_t len = sizeof(*addr);
int connfd = ::accept(listenfd, (struct sockadr*)addr, &len);
//...
}
貼一個(gè)man 2 accept
:
The addrlen argument is a value-result argument: the caller must initialize it to contain the size (in bytes) of the structure pointed to by addr; on return it will contain the actual size of the.