(分享)winsock 编程基础 之 阻塞 I/O 模型
程序代码:
WSAData wsaDate; //声明一个WSADate结构体(包含了Winsock库的版本信息)变量 int nRet=WSAStartup(MAKEWORD(2,2),&wsaDate); //初始化该结构体(协商版本) 若返回0则成功 //if(nRet!=0) //错误处理 sockaddr_in saServer; //声明一个地址结构体 sockaddr是系统自己使用的 saServer.sin_family=AF_INET; //必须是AF_INET saServer.sin_port=htons(10000); //必须转换成网络字节序 htonl/htons (host to net long/ short) saServer.sin_addr.s_addr=htonl(INADDR_ANY); //接收任意IP的数据 (通配地址) //数字是short 字符long SOCKET sasocket; //声明一个套接字句柄变量 sasocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//使用UDP时的参数SOCK_DGRAM IPPROTO_UDP bind(sasocket,(sockaddr*)&saServer,sizeof(saServer));//绑定成功返回0 否则SOCK_ERROR listen(sasocket,1);//backlog表示可以接受的客服请求的最大数量 监听成功返回0 SOCK_ERROR sockaddr_in saClient; //客服端的地址结构体 int nsaClient=sizeof(sockaddr); //客服端地址信息的大小 SOCKET hClientsocket=accept(sasocket,(sockaddr*)&saClient,&nsaClient);//接收客服端的连接请求 //返回的套接字将用于与这个客服的连接 sasocket可以继续接受其他客服请求 //如果请求队列为空 那么将被阻塞 失败返回INVALID_SOCKET const int buff_len=1024; char recvbuff[buff_len+1]; nRet=recv(hClientsocket,recvbuff,buff_len,0);//返回接收数据的实际大小 失败返回SOCKET_ERROR flags参数有MSG_PEEK MSG_OOB 或一起使用 //如果系统能接收的最大数据量为len 那么recv将返回len 但不能超过buff_len //如果系统缓存区满了 那么调用recv的线程将被阻塞(停止运行) ,直到系统可以接收数据 //************确保接收(发送)全部数据******************************************************** int nbuff_len=520;//假设要接受的数据大小为520 int nn=0; while(nbuff_len>0) { int ret=recv(hClientsocket,&recvbuff[nn],nbuff_len,0); //nn在增加 nbuff_len在递减 if(ret=SOCKET_ERROR) //发送失败 就这一种情况 { //错误处理 } else if(ret==0) { //连接被发送方关闭,错误处理 } nn+=ret; nbuff_len-=ret; } //********************************************************************************************** int nSend=send(hClientsocket,recvbuff,nRet,0);//把接收到的实际数据的大小发送出去 flags参数有MSG_DONTROUTE MSG_OOB 或一起使用 //nRet不能超过系统接收的最大长度 SOCKET_ERROR // shutdown(hClientsocket,SD_SEND);//SOCKET_ERROR 如果是UDP 此操作不需要 因为每次发送(接收)的都是完整的数据报 //shutdown之后还在接收数据 //do //{ 数据流还在流向接收端直到全部到达 //ret=recv(hClientsocket,&recvbuff[nn],nbuff_len,0); //}while(ret!=0) //如果ret==0了 closesocket(hClientsocket);//SOCKET_ERROR WSACleanup();//清除关于winsock的一切资源
学习笔记分享下