select模型超时的一点理解和问题

dhbo 2005-06-24 12:40:55
一直想学学socket编程,近几天买了电脑才有自己的时间和空间。
我写了一点




#include "stdafx.h"

#include "winsock2.h"
#include "iostream.h"


#pragma comment(lib,"Ws2_32.lib")

#define OK 0
#define FAIL -1
#define MAX_LEN 255
#define SERVER_PORT 8000
#define MAX_LISTEN 5

CRITICAL_SECTION cs_a;

SOCKET s_newclient[MAX_LEN] ={0};

char szSend[MAX_LEN]="send string !" ;
// 写错误日志,方法不好
void WriteErrorLog(char *strerr,const char * filename="c:\\errlog.txt" )
{

char *perr = new char[strlen(strerr)+6] ;
strcpy(perr,strerr) ;
strcat(perr,"\r\n") ;
InitializeCriticalSection(&cs_a) ;
EnterCriticalSection(&cs_a);
FILE *fp = fopen(filename,"a+") ;
fwrite(perr,sizeof(char),strlen(perr),fp) ;
fclose(fp) ;
LeaveCriticalSection(&cs_a) ;
DeleteCriticalSection(&cs_a) ;

delete [] perr;


}
//取得本地的第一个网卡的IP,但是如果出错,不知道该怎么返回:(
in_addr GetLocalAddress()
{
char szname[MAX_LEN] ;
int iret = gethostname(szname,sizeof(szname)) ;
if(iret == SOCKET_ERROR)
{
sprintf(szname,"call gethost name fail,error code :%d",WSAGetLastError()) ;
WriteErrorLog(szname) ;
WSACleanup() ;
// return (in_addr *)0 ;
// 怎么返回一个类似NULL得in_addr
}
struct hostent *phtent =gethostbyname(szname) ;
return *(in_addr *)phtent->h_addr_list[0] ;



}
// 本来打算如果主机能够与client建立多线程的(与每个连接的client建立一个通信线程)
void DoSthWithNewSock(SOCKET s)
{
char szContent[MAX_LEN] ;
int iret = recv(s,szContent,MAX_LEN,0) ;
//如果socket已经关闭
if(iret == 0)
{
closesocket(s);
return;
}
//如果recv失败
else if(iret ==SOCKET_ERROR)
{
sprintf(szContent,"call recv fail,error code :%d",WSAGetLastError()) ;
WriteErrorLog(szContent) ;
WSACleanup() ;
return ;
}
else
{

iret = send(s,szContent,strlen(szContent),0) ;
if(iret ==SOCKET_ERROR )
{
sprintf(szContent,"call send error,error code:%d",WSAGetLastError()) ;
WriteErrorLog(szContent) ;
closesocket(s) ;
WSACleanup() ;
return ;
}

return ;

}


}

int main(int argc, char* argv[])
{

printf("Hello World!\n");

WSADATA wsadata ;
WORD uVersion = MAKEWORD(2,2) ;
int iret = WSAStartup(uVersion,&wsadata) ;
char szerror[MAX_LEN] ;
if(iret!=OK)
{
sprintf(szerror,"WsaStartup call fail,error code : %d",WSAGetLastError()) ;
WriteErrorLog(szerror) ;
WSACleanup() ;
return FAIL ;
}

SOCKET s = socket(AF_INET,SOCK_STREAM,0) ;
if(s==INVALID_SOCKET)
{
sprintf(szerror,"socket call fail ,error code :%d",WSAGetLastError()) ;
WriteErrorLog(szerror) ;
WSACleanup() ;
return FAIL ;
}


sockaddr_in s_sock,s_client ;
s_sock.sin_family = AF_INET ;
s_sock.sin_port =htons(SERVER_PORT) ;
s_sock.sin_addr = GetLocalAddress() ;

iret = bind(s,(sockaddr *)&s_sock,sizeof(sockaddr)) ;
if(iret == SOCKET_ERROR)
{
sprintf(szerror,"bind call fail,error code :%d",WSAGetLastError()) ;
WriteErrorLog(szerror) ;
WSACleanup() ;
return FAIL ;
}

iret = listen(s,MAX_LISTEN) ;
if(iret == SOCKET_ERROR )
{
sprintf(szerror,"listen call fail,error code :%d",WSAGetLastError());
WriteErrorLog(szerror);
WSACleanup() ;
return FAIL ;
}

fd_set fdread,fdwrite ;
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_SET(s,&fdread) ;
FD_SET(s,&fdwrite) ;
TIMEVAL tmval ;
int c_len =0 ;
tmval.tv_sec = 1 ;
tmval.tv_usec = 0 ;

int iTimeout = 3000 ;
//setsockopt(s,SOL_SOCKET ,SO_SNDTIMEO,(char *)&iTimeout,sizeof(TIMEVAL)) ;
//设置发送超时
//从网上查的,说是设置发送和接收的超时时间
//setsockopt(s,SOL_SOCKET ,SO_RCVTIMEO,(char *)&iTimeout,sizeof(TIMEVAL)) ;
//设置接受超时

//unsigned long ul = 1;
//ioctlsocket(s, FIONBIO, (unsigned long*)&ul); //设置为非阻塞模式
//网上找的,说是设置超时时间为1s


while(1)
{
iret = select(0,&fdread,&fdwrite,NULL,&tmval) ;


switch(iret)
{
case WSANOTINITIALISED:
break;
case WSAEFAULT:
break;
case WSAENETDOWN:
break ;
case WSAEINTR:
break ;
case WSAEINPROGRESS:
break;
case WSAENOTSOCK:
break ;
case WSAEINVAL:
break;
//垃圾代码,为了查看什么时候出现那几个返回i
case 0:
{
sprintf(szerror,"call select out time,error code :%d",WSAGetLastError()) ;
WriteErrorLog(szerror);
break ;
//超时返回,但是超时过后,select就返回10022错误,说是参数错误,为什么?

}
default:
{
sprintf(szerror,"call select fail,error code :%d",WSAGetLastError()) ;
WriteErrorLog(szerror);
closesocket(s) ;
WSACleanup() ;
return FAIL ;
}

}




if(FD_ISSET(s,&fdread))
{
SOCKET newSocket = accept(s,(sockaddr *)&s_client,&c_len) ;
if(newSocket == SOCKET_ERROR)
{
sprintf(szerror,"call accept error,error code : %d",WSAGetLastError()) ;

WriteErrorLog(szerror) ;
closesocket(s) ;
WSACleanup() ;
return FAIL ;
}

DoSthWithNewSock(newSocket) ;

}
if(FD_ISSET(s,&fdwrite))
{

iret = send(s,szSend,strlen(szSend),0) ;
if(iret == SOCKET_ERROR)
{
sprintf(szerror,"call send at main fail,error code :%d",WSAGetLastError()) ;
//closesocket(s) ;
return FAIL;
}

}




}




return 0;
}


以上是我的烂代码,我第一次写点,对select有一点理解是:(看书,没写理解深刻估计)
1)select模型是阻塞模型
它是为了管理多个SOCKET,如果不自己设置超时时间,那么就一直阻塞
但是如果设置了超时时间,难道时间到了,就把原来的SOCKET s 给改变了?否则为什么select没有再次返回0(连接超时),唯一的解释是把服务器端的s给改变了
2)怎么和客户端建立多个连接呢?我想server和client建立多个线程,还没有想到这个的典型的应用是什么?(除了聊天室)


---初学者,欢迎大家扔鸡蛋(闪~~~^_^)
...全文
323 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
dhbo 2005-06-28
  • 打赏
  • 举报
回复
非常感谢Practise_Think(时代“过客”) t



softrain 2005-06-27
  • 打赏
  • 举报
回复
在windows下面开发处理多个套接字的程序,如果不是做服务器,建议使用event模型,
在数据IO能力和CPU使用效率上都比select异步模型强很多,而且使用也更简单。
举个例子,BT软件BitComet处理多个连接用的就是EVENT模型。
Practise_Think 2005-06-25
  • 打赏
  • 举报
回复
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_SET(s,&fdread) ;
FD_SET(s,&fdwrite) ;
TIMEVAL tmval ;
int c_len =0 ;
tmval.tv_sec = 1 ;
tmval.tv_usec = 0 ;

这段代码应加在while()循环里,但在select()之前
dhbo 2005-06-24
  • 打赏
  • 举报
回复
我得
if((iret = select(0,&fdread,&fdwrite,NULL,&tmval))==SOCKET_ERROR)
{

}
在超时过后,第二次就返回10022得错误,为什么啊
??
oyljerry 2005-06-24
  • 打赏
  • 举报
回复
WSAGetLastError来获得错误
建立多个连接,可以开线程
danielzhu 2005-06-24
  • 打赏
  • 举报
回复
UP
nuaawenlin 2005-06-24
  • 打赏
  • 举报
回复
1,超时返回值为0,你应该在判断iret 是否为0之前看看iret 是不是SOCKET_ERROR.然后用WSAGetLastError()来看是什么原因造成了错误

2,多个连接和单个连接在socket上没有什么分别,主要是你如何处理这些连接

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧