請問為何server端無法接收到資訊而timeout |
答題得分者是:aftcast
|
linux_ii
一般會員 發表:1 回覆:1 積分:0 註冊:2008-04-10 發送簡訊給我 |
同ㄧ個程式產生了客戶端和伺服端,客戶端產生broadcast的UDP封包,而伺服端並接收的資訊加入到MEMO控制項中,但不知為何一直收不到客戶端傳送的資訊。 Client [code cpp] #include class myMastClient { private: SOCKET m_socketfd; sockaddr_in m_recvaddr; u_long m_dest; public: myMastClient () { m_dest = htonl(INADDR_BROADCAST); } ~myMastClient () { } void SetDest( char *_dest ) { m_dest = inet_addr( _dest ); } //--------------------------------------------------------------------------- // ³s¤W address¬° addrªºserver int Connect (int _port) { WSADATA wsaData; BOOL bOptVal = TRUE; int bOptLen = sizeof(BOOL); int retval; if ((retval = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) { WSACleanup(); return errno; } m_socketfd = socket(AF_INET, SOCK_DGRAM, 0); //IPPROTO_UDP if (m_socketfd == INVALID_SOCKET) { closesocket(m_socketfd); return errno; } m_recvaddr.sin_family = AF_INET; m_recvaddr.sin_port = htons(_port); m_recvaddr.sin_addr.s_addr = m_dest ; setsockopt(m_socketfd, SOL_SOCKET, SO_BROADCAST, (char*)&bOptVal, bOptLen); return 0; } int Send (char *msg, int len) { return sendto(m_socketfd,msg,len,0,(SOCKADDR *) &m_recvaddr,sizeof(m_recvaddr)); } int Recv (char *buf, int buf_len, int timeout) { int recvaddrsize = sizeof(m_recvaddr); int recv_len; fd_set iofds,iofds2; struct timeval tv, *ptv; int nfds , max_fd; FD_ZERO(&iofds); FD_SET(m_socketfd,&iofds); /* set timeout */ if( timeout > 0 ) { tv.tv_sec = timeout; tv.tv_usec = 0; ptv = &tv; } else { ptv = NULL; } /* select */ max_fd = m_socketfd; memcpy(&iofds2 , &iofds , sizeof(iofds2)); nfds = select( max_fd 1 , &iofds2 , (fd_set *)0 , (fd_set *)0, ptv ); if( nfds < 0 ) { /* == 0 , timeout , < 0 , error */ return WSAGetLastError(); } else if( nfds == 0 ) { return 0; } /* receive data */ if(FD_ISSET(m_socketfd , &iofds2)) { recv_len = recvfrom(m_socketfd,buf,buf_len,0,(SOCKADDR *)&m_recvaddr,&recvaddrsize); if( recv_len > 0 ) { buf[recv_len] = 0; /* ShowMsg(inet_ntoa(m_recvaddr.sin_addr)); ShowMsg(buf); */ return recv_len; } else { return WSAGetLastError(); } } return 0; } void Close () { closesocket(m_socketfd); WSACleanup(); } }; [/code] Server [code cpp] //--------------------------------------------------------------------------- #include #include"myheader.h" void ReportError(int, const char *); class myMastServer { private: SOCKET m_socketfd; sockaddr_in m_sendaddr; u_long m_dest; int nret; public: myMastServer () { m_dest = htonl(INADDR_ANY); } ~myMastServer () { } int Listen (int _port) { WSADATA wsaData; int retval; retval = WSAStartup(MAKEWORD(2, 2), &wsaData); if (retval != 0) { WSACleanup(); return WSAGetLastError(); } m_socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (m_socketfd == INVALID_SOCKET) { nret = WSAGetLastError(); ReportError(nret, "socket()"); WSACleanup(); closesocket(m_socketfd); return NETWORK_ERROR; } m_sendaddr.sin_family = AF_INET; m_sendaddr.sin_port = htons(_port); m_sendaddr.sin_addr.s_addr = m_dest; if( bind(m_socketfd, (SOCKADDR *) &m_sendaddr, sizeof(m_sendaddr)) == SOCKET_ERROR) { nret = WSAGetLastError(); ReportError(nret, "bind()"); WSACleanup(); return NETWORK_ERROR; } return 0; } int Recv (char *buf, int buf_len, int timeout) { int sendaddrsize = sizeof(m_sendaddr); int recv_len; fd_set iofds,iofds2; struct timeval tv, *ptv; int nfds , max_fd; FD_ZERO(&iofds); FD_SET(m_socketfd,&iofds); /* timeout */ if( timeout > 0 ) { tv.tv_sec = timeout; tv.tv_usec = 0; ptv = &tv; } else { ptv = NULL; } /*select */ max_fd = m_socketfd; memcpy(&iofds2 , &iofds , sizeof(iofds2)); nfds = select( max_fd 1 , &iofds2 , (fd_set *)0 , (fd_set *)0, ptv ); if( nfds < 0 ) { /* == 0 , timeout , < 0 , error */ return WSAGetLastError(); } else if( nfds == 0 ) { return 0; } /* receive data */ if(FD_ISSET(m_socketfd , &iofds2)) { recv_len = recvfrom(m_socketfd,buf,buf_len,0,(SOCKADDR *)&m_sendaddr,&sendaddrsize); if( recv_len > 0 ) { buf[recv_len] = 0; /* ShowMsg(inet_ntoa(m_sendaddr.sin_addr)); ShowMsg(buf); */ return recv_len; } else { return WSAGetLastError(); } } return 0; } void Close () { closesocket(m_socketfd); WSACleanup(); } }; [/code] Unit1.cpp [code cpp] #include #pragma hdrstop #include "Unit1.h" #include "myMastServer.h" #include "myMastClient.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; myMastServer *server; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { myMastClient *client = new myMastClient(); client->Connect(9521); client->Send("abcde",5); client->Close(); delete client; Memo1->Lines->Add("Respond"); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { Button2->Enabled = false; Memo1->Lines->Add("Start"); char buf[1024]; int len; server = new myMastServer(); server->Listen(9521); len = server->Recv(buf,sizeof(buf),5); if( len > 0 ) Memo1->Lines->Add(buf); else Memo1->Lines->Add("timeout"); Memo1->Lines->Add("End"); server->Close(); delete server; Button2->Enabled = true; } //--------------------------------------------------------------------------- [/code] Clinet button按下去馬上就會出現 Respond,但是Server Button按下去,會出現Start ,timeout,end,就是收不到資料,可否請高手幫忙看一下 我找好久不知問題在哪裡 |
aftcast
站務副站長 發表:81 回覆:1485 積分:1763 註冊:2002-11-21 發送簡訊給我 |
1/ 應該是先按server,再按client,有順序性的
2/ server 事件中的 Recv 裡是不是該有 while(1) 包起來? 不然5秒若過時了,就不會再資料。 3/測式期間,方便的話也把client事件中的send用while(1)包一下,這樣方便看結果。當然若是測沒問題,就把while取消! 沒詳看程式碼,但覺得你好像是參考別人的程式碼? 若是,那程式應該不會有錯… 總之,先試一下吧!
------
蕭沖 --All ideas are worthless unless implemented-- C++ Builder Delphi Taiwan G+ 社群 http://bit.ly/cbtaiwan |
linux_ii
一般會員 發表:1 回覆:1 積分:0 註冊:2008-04-10 發送簡訊給我 |
|
aftcast
站務副站長 發表:81 回覆:1485 積分:1763 註冊:2002-11-21 發送簡訊給我 |
1/ 我竟一時忘了你的接收是放在事件裡。這意味著若用while(1)會死當! 因為click事件是屬於send message 若沒有脫離事件,整個主form就會掛死在那裡。
同理,你的recv裡有用select指令,而這也是會造成類似while的等待5秒,而在這5秒未到時,也會因為沒脫離事件而掛死,進而clinet根本無法按。而當你可以按client時,server的物件早也delete了…故什麼也收不到 2/ 被擋的情形是會發生在跨router的情形。也就是一台在router的左邊,一台在router的右邊,這二台就彼此收不到。但若是二台都是router的同一邊,就不會有這問題 3/ 第2的問題是先天的。第1個問題才是程式上的問題,要去解決! 正統的解決方式都是用thread的型式來接收資料。不好的方式也有,就是你要把程式寫成2隻。假設server叫s.exe,client的叫c.exe s 的click事件裡一定要用while(1)來包recv。 當s程式開啟並按下按鈕後,s程式就會疑似當機的情形,但socket是在一直跑的! 只是因為s是ui的程式,畫面會有掛死的樣子。 s按下後,就再執行c程式,然後送封包給s 一般來說,若你的s程式是ui有畫面的,就要在s中額外的產生thread來收,ui才不會受影響。 若你一定要server和client同在一個程式中,那就一定要用thread來收,不然就像現在一樣,無論如何也收不到! ===================引 用 linux_ii 文 章=================== 1. 試了先按server後 就會先等到出現timeout後 才能按下client鍵,我想有沒有可能是因為設定為blocking mode,而程式會一直停在listen等到timeout後才會返回? 2. 也試過已迴圈方式,還是收不到 3. 看到windows網路與通訊程式設計書上寫著,udp broadcast 封包對於router會自動被擋掉,有可能是這個原因,因為PC是直接接DIR-300 router,所以收不到。
------
蕭沖 --All ideas are worthless unless implemented-- C++ Builder Delphi Taiwan G+ 社群 http://bit.ly/cbtaiwan |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |