Windows sockets 网络编程(二) — 阻塞模式开发

一、套接字的阻塞模式

        Windows Sockets 套接字模式用于当一个套接字被调用时,决定调用函数的阻塞行为。套接字模式有阻塞非阻塞两种工作模式。

       在阻塞模式下,在I/O操作完成之前,执行的操作函数将一直等候而不会立即返回,该函数所在的线程会阻塞在这里。

       例如当调用recv()函数时,系统首先检查是否有准备好的数据。如果数据没有准备好,系统就处于等待状态。当数据准备好后,将数据从系统缓冲区复制到用户空间,然后该函数返回。因为在Sockets 应用程序中,当调用recv()函数时,用户空间未必就已经存在数据,此时recv()函数就会阻塞在那里。

二、可能阻塞套接字的API调用

       当使用socket()函数和WSASocket()函数创建socket时,默认的socket都是阻塞的。

       但是并不是所有的Windows Sockets API 以阻塞套接字为参数都会发生阻塞。例如,以阻塞套接字为参数调用bind()、listen()等函数时,会立即返回。

        可能阻塞套接字的Windows Sockets API 调用分为以下4种:

       1. 输入操作
           recv()、recvfrom()、WSARecv()和WSARecvfrom()函数。

        2. 输出操作
           send()、sendto()、WSASend()和WSASendto()函数。

        3. 接受连接
           accept()和WSAAccept()函数。

        4. 外出连接
           connect()和WSAConnect()函数。

三、阻塞模式套接字的优势和不足

       优势:简单、容易实现。

       不足:在大量建立好的套接字线程之间进行通信比较困难,无法同时处理大量套接字。

四、实例

       以一个服务器和客户端相互问候的C/S程序为例。

       1. 服务器实现

               #include <iostream>
               #include <Winsock2.h>
               using namespace std;

               int main()
               {
                        //初始化Windows Sockets 动态库
                        WSADATA wsaData;
                         if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
                       {
                                    cout<<"找不到可使用的WinSock dll!"<<endl;
                                     return 1;
                         }

                        //创建套接字
                        SOCKET sListen=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
                         if(sListen==INVALID_SOCKET)
                        {
                                    cout<<"创建socket失败!"<<endl;
                                    WSACleanup();
                                     return 1;
                         }

                        //绑定套接字
                        SOCKADDR_IN addrServ;
                        addrServ.sin_family=AF_INET;
                        addrServ.sin_port=htons(5811);
                         addrServ.sin_addr.S_un.S_addr=INADDR_ANY;

                         if(bind(sListen,(sockaddr *)&addrServ,sizeof(sockaddr))==SOCKET_ERROR)
                       {
                                     cout<<"绑定socket失败!"<<endl;
                                     closesocket(sListen);
                                   WSACleanup();
                                     return 1;
                         }

                        //监听套接字
                        if(listen(sListen,10)==SOCKET_ERROR)
                        {
                                   cout<<"监听socket失败!"<<endl;
                                   closesocket(sListen);
                                     WSACleanup();
                                     return 1;
                         }

                        cout<<"服务器启动成功!"<<endl;
                        cout<<"正在等待客户端连接..."<<endl;

                        while(1)
                        {
                                    //接受客户端连接
                                    SOCKADDR_IN addrClient;
                                     int addrlen=sizeof(SOCKADDR_IN);
                                    memset(&addrClient,0,sizeof(SOCKADDR_IN));
                                   SOCKET clientSock=accept(sListen,(sockaddr *)&addrClient,&addrlen);
                                   if(clientSock==INVALID_SOCKET)
                                    {
                                                cout<<"接受socket连接出错!"<<WSAGetLastError()<<endl;
                                               continue;
                                     }

                                    //输出客户端信息
                                    char *strClientAddr=inet_ntoa(addrClient.sin_addr);
                                   unsigned short port=ntohs(addrClient.sin_port);
                                    cout<<"客户端IP:"<<strClientAddr<<",端口号:"<<port<<endl;

                                    //发送数据
                                    int retval=send(clientSock,"Hello,Client!",strlen("Hello,Client!"),0);
                                    if(retval==SOCKET_ERROR)
                                    {
                                                cout<<"发送数据失败!"<<endl;
                                    }

                                    //接收数据
                                   char buf[20];
                                    memset(buf,0,20);
                                    retval=recv(clientSock,buf,20,0);
                                    if(retval==SOCKET_ERROR)
                                    {
                                                cout<<"接收数据失败!"<<endl;
                                    }
                                     cout<<buf<<endl;
                       }

                       //关闭套接字,释放资源
                       closesocket(sListen);
                        WSACleanup();

                       return 0;
               }

       2. 客户端实现

               #include <iostream>
               #include <Winsock2.h>
               using namespace std;

               int main()
               {
                        //初始化Windows Sockets 动态库
                        WSADATA wsaData;
                        if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
                        {
                                   cout<<"找不到可使用的WinSock dll!"<<endl;
                                    return 1;
                        }

                        //创建套接字
                        SOCKET sClient=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
                        if(sClient==INVALID_SOCKET)
                        {
                                  cout<<"创建客户端socket失败!"<<endl;
                                  return 1;
                         }

                        //连接服务器
                        SOCKADDR_IN addrServ;
                        addrServ.sin_family=AF_INET;
                        addrServ.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
                        addrServ.sin_port=htons(5811);
                        if(connect(sClient,(sockaddr *)&addrServ,sizeof(sockaddr))==SOCKET_ERROR)
                        {
                                 cout<<"连接服务器失败!"<<endl;
                                 closesocket(sClient);
                                 return 1;
                        }
                        else
                                 cout<<"连接服务器成功!"<<endl;

                        //发送数据
                        int retval=send(sClient,"Hello,Server!",strlen("Hello,Server!"),0);
                        if(retval==SOCKET_ERROR)
                        {
                                cout<<"发送数据失败!"<<endl;
                        }

                        //接收数据
                        char buf[20];
                        memset(buf,0,20);
                         retval=recv(sClient,buf,20,0);
                        if(retval==SOCKET_ERROR)
                        {
                                cout<<"接收数据失败!"<<endl;
                         }
                        cout<<buf<<endl;

                        //关闭套接字,释放资源
                        closesocket(sClient);
                        WSACleanup();

                        return 0;
               }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值