線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:2603
推到 Plurk!
推到 Facebook!

請問為何server端無法接收到資訊而timeout

答題得分者是:aftcast
linux_ii
一般會員


發表:1
回覆:1
積分:0
註冊:2008-04-10

發送簡訊給我
#1 引用回覆 回覆 發表時間:2008-11-05 00:19:35 IP:61.62.xxx.xxx 訂閱


同ㄧ個程式產生了客戶端和伺服端,客戶端產生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,就是收不到資料,可否請高手幫忙看一下 我找好久不知問題在哪裡
編輯記錄
linux_ii 重新編輯於 2008-11-05 08:51:27, 註解 無‧
linux_ii 重新編輯於 2008-11-05 09:13:49, 註解 無‧
aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#2 引用回覆 回覆 發表時間:2008-11-06 05:27:16 IP:59.115.xxx.xxx 訂閱
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
編輯記錄
aftcast 重新編輯於 2008-11-06 05:29:05, 註解 無‧
aftcast 重新編輯於 2008-11-06 09:42:16, 註解 無‧
linux_ii
一般會員


發表:1
回覆:1
積分:0
註冊:2008-04-10

發送簡訊給我
#3 引用回覆 回覆 發表時間:2008-11-06 10:24:44 IP:61.62.xxx.xxx 訂閱
1. 試了先按server後 就會先等到出現timeout後 才能按下client鍵,我想有沒有可能是因為設定為blocking mode,而程式會一直停在listen等到timeout後才會返回?
2. 也試過已迴圈方式,還是收不到
3. 看到windows網路與通訊程式設計書上寫著,udp broadcast 封包對於router會自動被擋掉,有可能是這個原因,因為PC是直接接DIR-300 router,所以收不到。
aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#4 引用回覆 回覆 發表時間:2008-11-06 11:45:29 IP:59.115.xxx.xxx 訂閱
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
系統時間:2017-10-24 17:39:49
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!