分类 网络编程 下的文章

在Select模型中,可以使Windows Sockets应用程序同时对多个Socket进行管理,调用select()函数可以获取指定Socket的状态。

1、Select()函数
Select()函数可以决定一组Socket的状态,通常操作于就绪的Socket。使用fd_set结构体来管理多个Socket。

typedef struct fd_set{
    u_int fd_count;
    SOCKET fd_arrat[FD_SETSIZE];
}fd_set;

参数fd_count表示集合中包含的Socket数目,fd_array是保存Socket的数组。

- 阅读剩余部分 -

默认情况下,新建的Socket是阻塞模式的。可以调用ioctlsocket()函数将Socket设置为非阻塞模式,函数原型如下:

int ioctlsocket(SOCKET s,long cmd,u_long* argp)

参数说明:
s:Socket句柄;
cmd:在s上执行的命令;
argp:指针变量,指定cmd命令的参数,当cmd设为FIONBIO时,argp非0,表示启用非阻塞模式。

1、非阻塞模式服务器
(1)接收来自客户端请求
由于启用非阻塞模式,accept函数调用后会立即返回,无论是否有客户连接,所以需要每隔一段时间调用探测。

client=accept(server,(sockaddr*)&cAddr,&len);
if(client==INVALID_SOCKET)
{
    int err=WSAGetLastError();
    // 当前socket被表示为非阻塞,没有连接
    if(err==WSAEWOULDBLOCK)
    {
        Sleep(100);
        continue;
    }
    else
    {
        cout<<"accept error"<<endl;
        closesocket(server);
        WSACleanup();
        return -1;
    }
}

- 阅读剩余部分 -

Socket编程模型分成阻塞和非阻塞两种开发模式。
阻塞模式是指在指定Socket上调用函数执行操作,在没有完成操作前,函数不会立即返回。例如,服务器调用accept函数是会阻塞服务器线程,知道接收到一个来自客户端的连接请求。默认创建的Socket是阻塞模式。
非阻塞模式是指在指定Socket上调用函数执行操作,无论操作是否完成,函数都会立即返回,不会一直挂在此函数的调用上。

在实际开发中,服务器需要和多个客户端进行通信,为了提高服务器并发能力,通常为每个客户端启动一个线程。Windows提供了5中Socket编程模型,即Select模型、WSAAsyncSelect模型、WSAEventSelect模型、重叠I/O模型和完成端口模型。

1、Select模型
Select模型又称选择模型,它可以同时对多个Socket进行管理,调用Select()函数获取制定Socket的状态,然后调用Windows Socket API实现数据发送接收。
Socket()函数使用集合来进行管理多个Socket,默认情况下,集合最多含64个元素,最多可以管理的Socket数量为1024。每次在Socket发送和接收数据前,都需要调用Select()判别Socket的状态。
http://tanhp.com/index.php/archives/222/

- 阅读剩余部分 -

有些情况下,我们需要对Socket行为和属性进一步控制,例如修改缓冲区大小,查看Socket状态,这就需要设置/获取Socket选项。

1、获取Socket选项
int getsockopt(SOCKET s,int level,int optname,void *optval,int *optlen)
s:Socket描述符
level:选项级别,包括SOL_SOCKETIPPROTO_TCP
optname:Socket选项的名字
optval:用于接收Socket数值的缓冲区
optlen:缓冲区大小

例如:

int optVal;
int optLen=sizeof(optVal);
// getsocketopt
getsockopt(ListenSocket,SOL_SOCKET,SO_ACCEPTCONN,(char*)&optVal,&optLen);
cout<<"SO_ACCEPTCONN:"<<optVal<<endl;

- 阅读剩余部分 -

与面向连接的网络连接相比,无连接的网络通信不需要在服务器与客户端之间建立连接。面向非连接的Socket通信是基于UDP的,服务器端不需要调用listen()accept()函数来等待客户端的连接;客户端直接向服务器发送数据。

1、服务器端
(1)建立Socket,绑定本地IP和端口

server=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
sAddr.sin_family=AF_INET;
sAddr.sin_port=htons(9000);
sAddr.sin_addr.s_addr=htonl(ADDR_ANY);
retVal=bind(server,(sockaddr*)&sAddr,sizeof(sAddr));

(2)等待客户连接、接收数据

sockaddr_in recvAddr;
int len=sizeof(recvAddr);
// 连接的客户端地址信息

recvfrom(server,buf,BUF_SIZE,0,(sockaddr*)&recvAddr,&len);
cout<<"Recv date from "<<inet_ntoa(recvAddr.sin_addr)<<" :"<<buf<<endl;
// 接收数据、recvAddr返回客户段信息

(3)发送数据

sendto(server,buf,strlen(buf),0,(sockaddr*)&recvAddr,len);

- 阅读剩余部分 -