服务器能接收信息,而客户端不能?(视频会议代码)
我下载了一个源码.服务器和客户端的CTCP.cpp类都是相同代码:int CTCP::InitTCPNumber = 0;
CTCP::CTCP()
{
if( CTCP::InitTCPNumber == 0 )
{
WSADATA data;
::WSAStartup( MAKEWORD( 2 , 1 ) , &data );
}
CTCP::InitTCPNumber ++ ;
this->s_listen = INVALID_SOCKET;
this->connect_socket = INVALID_SOCKET;
this->user_data = 0;
this->visit = 0;
::InitializeCriticalSection( &this->session );
}
CTCP::~CTCP()
{
CTCP::InitTCPNumber -- ;
if( CTCP::InitTCPNumber == 0 )
::WSACleanup( );
::DeleteCriticalSection( &this->session );
}
char * CTCP::GetIPAddressFromHostName( void )
{
char hostname[ HOST_NAME_LEHGTH ];
::gethostname( hostname , HOST_NAME_LEHGTH );
hostent * ent = ::gethostbyname( hostname );
sockaddr_in addr;
memcpy( &addr.sin_addr , ent->h_addr , ent->h_length );
return ::inet_ntoa( *( in_addr * )&addr.sin_addr.s_addr );
}
char * CTCP::GetPeerName( void )
{
sockaddr_in addr;
int len = sizeof( addr );
::getpeername( this->connect_socket , ( SOCKADDR * )&addr , &len );
return ::inet_ntoa( *( in_addr * )&addr.sin_addr.s_addr );
}
char * CTCP::GetSockName( void )
{
sockaddr_in addr;
int len = sizeof( addr );
::getsockname( this->connect_socket , ( SOCKADDR * )&addr , &len );
return ::inet_ntoa( *( in_addr * )&addr.sin_addr.s_addr );
}
bool CTCP::Create( void ( * OnAccept )( void *pContext , CTCP & server ) , void * pContext , const int port )
{
if( this == NULL ) return false;
if( this->IsListen( ) ) return true;
sockaddr_in addr;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_family=AF_INET;
addr.sin_port=::htons( port );
//创建套接字
SOCKET s = ::socket( AF_INET , SOCK_STREAM , IPPROTO_TCP );
if(s == INVALID_SOCKET)
{
return false;
}//绑定套接字
if(::bind( s , ( SOCKADDR * )&addr,sizeof( addr ) ) == SOCKET_ERROR )
{
closesocket( s ); return false;
}//监听套接字
if( ::listen( s , 5 ) == SOCKET_ERROR )
{
closesocket( s ); return false;
}
this->s_listen = s;
CInfo * info = new CInfo( OnAccept , pContext , this );
CThread::Run( CTCP::OnAccept , info );
return true;
}
void CTCP::OnAccept( void * pContext )
{
CInfo * info = ( CInfo * )pContext;
sockaddr_in addr;
int len=sizeof(addr);
for( ; ; )
{
if( ( info->pThis->connect_socket = ::accept( info->pThis->s_listen , ( SOCKADDR * )&addr , &len ) ) == INVALID_SOCKET )
break;
info->OnAccept( info->pContext , * info->pThis );
}
info->pThis->Close( );
delete info;
}
bool CTCP::Accept( CTCP * client )
{
if( this == NULL || this->connect_socket == INVALID_SOCKET )
return false;
client->connect_socket = this->connect_socket;
this->connect_socket = INVALID_SOCKET;
return true;
}
bool CTCP::Connect( const char * ip , const port )
{
if( this == NULL )
return false;
if( this->IsConnected( ) )
return true;
sockaddr_in addr;
addr.sin_addr.s_addr=::inet_addr(ip);
addr.sin_family=AF_INET;
addr.sin_port=::htons(port);
//创建套接字
if( ( this->connect_socket = ::socket( AF_INET , SOCK_STREAM , IPPROTO_TCP) ) == INVALID_SOCKET )
return false;
//连接
if( ::connect( this->connect_socket , ( SOCKADDR * )&addr , sizeof( addr ) ) == SOCKET_ERROR )
{
this->Close( ); return false;
}
return true;
}
bool CTCP::IsConnected( void )
{
return this->connect_socket != INVALID_SOCKET;
}
bool CTCP::Send( CBuffer & buffer )
{
if( ! this || ! this->IsConnected( ) )
return false;
//锁定临界区
::EnterCriticalSection( &this->session );
//保存缓冲区
int s = 0 , size = *( int * )buffer.GetBuffer( );
//加密,后面的12个字节都填充ABC,表示头信息
char * now = buffer.GetBuffer( );
*( int * )now |= 0xABC00000;
//分次发送数据包
fd_set fd;
FD_ZERO( &fd );
FD_SET( this->connect_socket , &fd );
//分次发送
while( size > 0 && ::select( 0 , NULL , &fd , NULL , NULL ) > 0 && ( s = ::send( this->connect_socket , now , size , 0 ) ) > 0 )
{
size -= s;
now += s;
}//恢复信息
*( int * )buffer.GetBuffer( ) ^= 0xABC00000;
//返回是否连接
if( size > 0 )
this->Close( );
//解锁临界区
::LeaveCriticalSection( &this->session );
return this->IsConnected( );
}
bool CTCP::Receive( CBuffer & buffer , struct timeval * timeout )
{
if( ! this || ! this->IsConnected( ) )
return false;
int s = 0 , size = 1;
fd_set fd;
FD_ZERO( &fd );
FD_SET( this->connect_socket , &fd );
//接收数据包的大小
BYTE_INT_UNION BI;
BI.iValue = 0;
//一次读取一个字节,读出数据包的大小
while( ::select( 0 , &fd , NULL , NULL , timeout ) > 0 && ( size & 0xFFF00000 ) != 0xABC00000 )
{
BI.B.a = BI.B.b; BI.B.b = BI.B.c; BI.B.c = BI.B.d;
if( ::recv( this->connect_socket , ( char * )&BI.B.d , ( int )sizeof( BYTE ) , 0 ) <= 0 )
{
this->Close( ); break;
}
else
size = BI.iValue;
}//判断头标志,如果头标志接收错误,那么断开连接
if( ( size & 0xFFF00000 ) == 0xABC00000 )
{ //取出要接收缓冲区的大小
size ^= 0xABC00000;
//重新分配内存
if( buffer.GetSize( ) < size )
buffer.Resize( size );
char * now = buffer.GetBuffer( );
//保存大小且偏移4个字节
*( int * )now = size; now += sizeof( int ); size -= sizeof( int );
//循环接收数据
while( size > 0 && ::select( 0 , &fd , NULL , NULL , NULL ) > 0 && ( s = ::recv( this->connect_socket , now , size , 0 ) ) > 0 )
{
now += s;
size -= s;
}
}//接收过程中出错,那么不处理
if( size > 0 )
{
buffer.Release( );
size = 1;
//判断是否可以发送出去
if( ::send( this->connect_socket , ( char * )&size , ( int )sizeof( char ) , 0 ) <= 0 )
this->Close( );
else
::Sleep( 100 );
}//返回是否连接
return this->IsConnected( );
}
void CTCP::Close( void )
{ //关闭监听
SOCKET s;
if( this->IsListen( ) )
{
s = this->s_listen;
this->s_listen = INVALID_SOCKET;
::closesocket( s );
}//关闭连接
if( this->IsConnected( ) )
{
s = this->connect_socket;
this->connect_socket = INVALID_SOCKET;
::closesocket( s );
}
}
服务器侦听和接受代码:
bool CServer::Run( const int port )
{
if( this->m_server.Create( CServer::OnAccept , this , port ) )
{
this->logFile.Write( "中央管理服务器初始化成功,正在监听端口 : %d ...\n" , port );
return true;
}
this->logFile.Write( "中央管理服务器初始化失败\n" );
return false;
}
void CServer::OnAccept( void * wParam , CTCP &server )
{
CServer * pThis = ( CServer * )wParam;
CTCP * client = new CTCP( );
client->SetData( ( int )pThis );
if( server.Accept( client ) )
{
pThis->logFile.Write( "服务器接收到一个连接\n" );
CThread::Run( CServer::OnCommand , client );
}
else
{
client->Close( );
delete client;
if( pThis->m_server.IsListen( ) )
{
pThis->logFile.Write( "服务器监听失败,再次启动服务器\n" );
}
}
}
客户端连接和接收代码:
bool CClient::Run( const char * IP , const int Port )
{
if( this->cmdTCP.Connect( IP , Port ) )
{
PChannelType cType;
if( cType.assembleData( PChannelType::COMMAND , 0 ) && this->cmdTCP.Send( cType.buffer ) )
{
this->serverIP = IP;
this->serverPort = Port;
::WriteLog( theApp.GetLogHwnd( ) , ( CString )"连接服务器" + ( CString )IP + ( CString )"成功" );
}
else
this->cmdTCP.Close( );
}
return this->cmdTCP.IsConnected( );
}
void CClient::OnCommand( void * pContext )
{
CClient * pThis = ( CClient * )pContext;
CBuffer buffer;
//2个数据包之间最大的时间间隔是5分钟
struct timeval tm = { 300 , 0 };
//无限等待
while( pThis->cmdTCP.Receive( buffer/* , &tm */ ) )
{ //取出数据出错,那么保持连接继续工作
if( ! buffer.GetSize( ) )
break;
try
{
switch( *( int * )( buffer.GetBuffer( ) + INT_SIZE ) )
{ //在线用户信息
case POnlineUserRESTAG : pThis->OnlineUserRES( buffer ); break;
//创建会议回复
case PCreateDataNodeRESTAG : pThis->OnCreateDataNodeRES( buffer ); break;
}
}
catch( ... )
{
}
}//断开所有连接
pThis->Stop( );
//写入日志
::WriteLog( theApp.GetLogHwnd( ) , "断开与服务器的连接" );
//通知界面更新
while( CTipDialog::IsWindow( ) ) ::Sleep( 100 );
//延时5秒钟
::Sleep( 5000 );
pThis->SendMsg( NULL );
}
//用户注册
int CClient::Register( const char * username , const char * password )
{
int ret = 3;
PRegisterREQ req;
//组合注册信息
if( req.assembleData( username , password , PRegisterREQ::MEETING ) && this->cmdTCP.Send( req.buffer ) )
{
CBuffer buffer;
PRegisterRES res;
if( this->cmdTCP.Receive( buffer ) && res.parseData( buffer ) )
{
if( ! res.ireturn )
{
//用户注册成功,增加视频通道和声音通道
PChannelType cType;
if( this->videoTCP.Connect( this->serverIP.c_str( ) , this->serverPort ) && cType.assembleData( PChannelType::VIDEO , res.user_id ) && this->videoTCP.Send( cType.buffer )
&&this->audioTCP.Connect( this->serverIP.c_str( ) , this->serverPort ) && cType.assembleData( PChannelType::AUDIO , res.user_id ) && this->audioTCP.Send( cType.buffer ) )
{ //延时一秒,等待服务器的处理
::Sleep( 1000 );
//保存用户名和密码
this->userName = username;
this->password = password;
//保存自己在服务器的id
this->user_id = res.user_id;
//启动命令线程
CThread::Run( CClient::OnCommand , this );
//启动音频线程
CThread::Run( CClient::OnAudio , this );
//启动视频线程
CThread::Run( CClient::OnVideo , this );
::WriteLog( theApp.GetLogHwnd( ) , "注册成功,连接音视频通道" );
ret = 0;
}
}
else
ret = res.ireturn;
}
}
}
服务器能接收到客户端的注册信息.但客户端却接收不了服务器信息.为什么?怎么处理?是不是while( pThis->cmdTCP.Receive( buffer/* , &tm */ ) )有问题?
[[italic] 本帖最后由 yeyuanzhi 于 2007-11-25 14:44 编辑 [/italic]]