c/c++语言开发共享C语言实现 select模式编程

server: // tcpserver.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include #incl


server:

  // tcpserver.cpp : 定义控制台应用程序的入口点。  //  #include "stdafx.h"  #include      #include     #pragma comment(lib,"ws2_32.lib")       #define   port   9990     #define   data_bufsize   8192       // 定义套接字信息  typedef   struct   _socket_information   {         char   buffer[data_bufsize];        // 发送和接收数据的缓冲区      wsabuf   databuf;                       // 定义发送和接收数据缓冲区的结构体,包括缓冲区的长度和内容      socket   socket;                            // 与客户端进行通信的套接字      dword   bytessend;                  // 保存套接字发送的字节数      dword   bytesrecv;                  // 保存套接字接收的字节数  } socket_information,   *   lpsocket_information;       dword   totalsockets = 0;               // 记录正在使用的套接字总数量  lpsocket_information   socketarray[fd_setsize];         // 保存socket信息对象的数组,fd_setsize表示select模型中允许的最大套接字数量    // 创建socket信息  bool   createsocketinformation(socket   s)     {         lpsocket_information   si;                                      // 用于保存套接字的信息          //   printf("accepted   socket   number   %dn",   s);         // 打开已接受的套接字编号      // 为si分配内存空间      if ((si = (lpsocket_information) globalalloc(gptr,                   sizeof(socket_information)))   ==   null)         {             printf("globalalloc()   failed   with   error   %dn",   getlasterror());             return   false;         }         // 初始化si的值          si->socket = s;         si->bytessend = 0;         si->bytesrecv = 0;         // 在socketarray数组中增加一个新元素,用于保存si对象       socketarray[totalsockets]   =   si;             totalsockets++;                     // 增加套接字数量        return(true);     }         // 从数组socketarray中删除指定的lpsocket_information对象  void   freesocketinformation(dword   index)     {         lpsocket_information si = socketarray[index];   // 获取指定索引对应的lpsocket_information对象      dword   i;         // 关闭套接字      closesocket(si->socket);         //printf("closing   socket   number   %dn",   si->socket);         // 释放指定lpsocket_information对象资源      globalfree(si);         // 将数组中index索引后面的元素前移      for (i = index; i < totalsockets; i++)         {             socketarray[i] = socketarray[i+1];         }          totalsockets--;        // 套接字总数减1  }       // 主函数,启动服务器  int _tmain(int argc, _tchar* argv[])  {      socket   listensocket;                  // 监听套接字      socket   acceptsocket;                  // 与客户端进行通信的套接字      sockaddr_in   internetaddr;         // 服务器的地址      wsadata   wsadata;                      // 用于初始化套接字环境      int   ret;                                          // winsock api的返回值      fd_set   writeset;                          // 获取可写性的套接字集合      fd_set   readset;                           // 获取可读性的套接字集合      dword   total = 0;                              // 处于就绪状态的套接字数量      dword   sendbytes;                      // 发送的字节数      dword   recvbytes;                      // 接收的字节数          // 初始化winsock环境      if ((ret = wsastartup(0x0202,&wsadata)) != 0)         {             printf("wsastartup()   failed   with   error   %dn",   ret);             wsacleanup();             return -1;         }         // 创建用于监听的套接字       if ((listensocket = wsasocket(af_inet, sock_stream, 0, null, 0,                   wsa_flag_overlapped))   ==   invalid_socket)           {             printf("wsasocket()   failed   with   error   %dn",   wsagetlasterror());             return -1;         }         // 设置监听地址和端口号      internetaddr.sin_family = af_inet;         internetaddr.sin_addr.s_addr = htonl(inaddr_any);         internetaddr.sin_port = htons(port);         // 绑定监听套接字到本地地址和端口      if(bind(listensocket, (psockaddr)&internetaddr, sizeof(internetaddr)) == socket_error)         {             printf("bind()   failed   with   error   %dn",   wsagetlasterror());             return -1;         }         // 开始监听      if   (listen(listensocket,   5))         {             printf("listen()   failed   with   error   %dn",   wsagetlasterror());             return -1;         }         /*  // 设置为非阻塞模式      ulong nonblock = 1;         if(ioctlsocket(listensocket, fionbio, &nonblock) == socket_error)         {             printf("ioctlsocket() failed with error %dn", wsagetlasterror());             return -1;         }         // 为listensocket套接字创建对应的socket_information      // 这样就可以把listensocket添加到socketarray数组中        */        createsocketinformation(listensocket);          while(true)         {             // 准备用于网络i/o通知的读/写套接字集合          fd_zero(&readset);             fd_zero(&writeset);             // 向readset集合中添加监听套接字listensocket          fd_set(listensocket,   &readset);             // 将socketarray数组中的所有套接字添加到writeset和readset集合中          // socketarray数组中保存着监听套接字和所有与客户端进行通信的套接字          // 这样就可以使用select()判断哪个套接字有接入数据或者读取/写入数据          for   (dword i=0; isocket,   &writeset);                 fd_set(socketinfo->socket,   &readset);             }          // 判断读/写套接字集合中就绪的套接字              if((total = select(0, &readset, &writeset, null, null)) == socket_error)             {                 printf("select()   returned   with   error   %dn",   wsagetlasterror());                 return -1;             }                // 依次处理所有套接字。本服务器是一个回应服务器,即将从客户端收到的字符串再发回到客户端。          for   (dword i=0; isocket,   &readset))                 {                     if(socketinfo->socket == listensocket)      // 对于监听套接字来说,可读表示有新的连接请求                  {                      total--;    // 就绪的套接字减1                      // 接受连接请求,得到与客户端进行通信的套接字acceptsocket                      if((acceptsocket = accept(listensocket, null, null))   !=   invalid_socket)                         {                             printf("连接成功!n");                          /*                          // 设置套接字acceptsocket为非阻塞模式                          // 这样服务器在调用wsasend()函数发送数据时就不会被阻塞                          nonblock   =   1;                             if(ioctlsocket(acceptsocket, fionbio, &nonblock)   ==   socket_error)                             {                                 printf("ioctlsocket()   failed   with   error   %dn",   wsagetlasterror());                                 return -1;                                                       }                             */                            // 创建套接字信息,初始化lpsocket_information结构体数据,将acceptsocket添加到socketarray数组中                          if(createsocketinformation(acceptsocket) == false)                                 return -1;                         }                         else                         {                             if(wsagetlasterror() != wsaewouldblock)                             {                                 printf("accept()   failed   with   error   %dn",   wsagetlasterror());                                 return -1;                             }                         }                                     }                  else   // 接收数据                  {                      // 如果当前套接字在readset集合中,则表明该套接字上有可以读取的数据                      if   (fd_isset(socketinfo->socket,   &readset))                         {                             total--;                // 减少一个处于就绪状态的套接字                          memset(socketinfo->buffer, ' ', data_bufsize);                            zeromemory(socketinfo->databuf.buf,data_bufsize);// 初始化缓冲区                          socketinfo->databuf.buf = socketinfo->buffer;           // 初始化缓冲区位置                          socketinfo->databuf.len   =   data_bufsize;             // 初始化缓冲区长度                          // 接收数据                          dword  flags = 0;                             if(wsarecv(socketinfo->socket, &(socketinfo->databuf), 1, &recvbytes, &flags,                               null, null) == socket_error)                             {                                 // 错误编码等于wsaewouldblock表示暂没有数据,否则表示出现异常                              if(wsagetlasterror() != wsaewouldblock)                                   {                                     printf("wsarecv()   failed   with   error   %dn",   wsagetlasterror());                                     freesocketinformation(i);       // 释放套接字信息                              }                                 continue;                             }                               else   // 接收数据                          {                                 socketinfo->bytesrecv = recvbytes;      // 记录接收数据的字节数                                                         if(recvbytes == 0)                                  // 如果接收到0个字节,则表示对方关闭连接                              {                                     freesocketinformation(i);                                     continue;                                 }                                 else                                                            // 如果成功接收数据,则打印收到的数据                              {                                  printf(socketinfo->databuf.buf);                                  printf("n");                                    //                              }                          }                      }                     }              }              else              {                  // 如果当前套接字在writeset集合中,则表明该套接字的内部数据缓冲区中有数据可以发送                  if(fd_isset(socketinfo->socket,  &writeset))                     {                         total--;            // 减少一个处于就绪状态的套接字                      socketinfo->databuf.buf = socketinfo->buffer + socketinfo->bytessend;           // 初始化缓冲区位置                      socketinfo->databuf.len = socketinfo->bytesrecv - socketinfo->bytessend;    // 初始化缓冲区长度                      if(socketinfo->databuf.len > 0)     // 如果有需要发送的数据,则发送数据                      {                          if(wsasend(socketinfo->socket, &(socketinfo->databuf), 1, &sendbytes, 0,                                             null, null) == socket_error)                             {                                 // 错误编码等于wsaewouldblock表示暂没有数据,否则表示出现异常                              if(wsagetlasterror() != wsaewouldblock)                                 {                                     printf("wsasend()   failed   with   error   %dn", wsagetlasterror());                                     freesocketinformation(i);       // 释放套接字信息                              }                                 continue;                             }                             else                             {                                 socketinfo->bytessend += sendbytes;         // 记录发送数据的字节数                              // 如果从客户端接收到的数据都已经发回到客户端,则将发送和接收的字节数量设置为0                              if (socketinfo->bytessend   ==   socketinfo->bytesrecv)                                 {                                     socketinfo->bytessend   =   0;                                     socketinfo->bytesrecv   =   0;                                 }                             }                         }                  }                               }   // 如果listensocket未就绪,并且返回的错误不是wsaewouldblock(该错误表示没有接收的连接请求),则出现异常            }                   }         // 暂停,按任意键退出      system("pause");      return 0;  }    

client:

  // tcpclient.cpp : 定义控制台应用程序的入口点。  //    #include "stdafx.h"    #include      #include   #include     #pragma comment(lib,"ws2_32.lib")     #define buf_size    64          // 缓冲区大小      int _tmain(int argc, _tchar* argv[])  {      wsadata     wsd;                    // 用于初始化windows socket         socket      shost;                  // 与服务器进行通信的套接字         sockaddr_in servaddr;           // 服务器地址         char        buf[buf_size];          // 用于接受数据缓冲区         int         retval;                         // 调用各种socket函数的返回值         // 初始化windows socket      if(wsastartup(makeword(2,2),&wsd) != 0)         {             printf("wsastartup failed !n");             return 1;         }           // 创建套接字         shost = socket(af_inet,sock_stream,ipproto_ip);         if(invalid_socket == shost)         {             printf("socket failed !n");             wsacleanup();             return -1;         }            // 设置服务器地址         servaddr.sin_family = af_inet;         servaddr.sin_addr.s_un.s_addr = inet_addr("127.0.0.1");     // 用户需要根据实际情况修改      servaddr.sin_port = htons(9990);                                                    // 在实际应用中,建议将服务器的ip地址和端口号保存在配置文件中      int sserveraddlen = sizeof(servaddr);                                               // 计算地址的长度             // 循环等待      while(true)      {          // 连接服务器             sleep( 200 );          retval = connect(shost,(lpsockaddr)&servaddr,sizeof(servaddr));             sleep( 200 );          if(socket_error == retval)             {                 int err = wsagetlasterror();              if(err == wsaewouldblock || err == wsaeinval)           // 无法立即完成非阻塞套接字上的操作              {                  //sleep(500);                  continue;              }              else if(err == wsaeisconn)                                              // 已建立连接              {                  break;              }              else              {                                  continue;                    //printf("connect failed !n");                     //closesocket(shost);                     //wsacleanup();                     //return -1;                 }          }         }      // 循环向服务器发送字符串,并显示反馈信息。      // 发送quit将使服务器程序退出,同时客户端程序自身也将退出      while(true)      {          // 向服务器发送数据             printf("please input a string to send: ");          // 接收输入的数据          std::string str;          std::getline(std::cin, str);          // 将用户输入的数据复制到buf中          zeromemory(buf,buf_size);            zeromemory(buf,buf_size);             strcpy(buf,str.c_str());             // 循环等待          while(true)          {              // 向服务器发送数据              retval = send(shost,buf,strlen(buf),0);                 if(socket_error == retval)                 {                     int err = wsagetlasterror();                  if(err == wsaewouldblock)           // 无法立即完成非阻塞套接字上的操作                  {                        continue;                  }                  else                  {                      printf("send failed !n");                         closesocket(shost);                         wsacleanup();                         return -1;                     }              }              break;          }                 while(true)          {              zeromemory(buf,buf_size);                       // 清空接收数据的缓冲区              retval = recv(shost,buf,sizeof(buf)+1,0);   // 接收服务器回传的数据                 if(socket_error == retval)                 {                     int err = wsagetlasterror();                // 获取错误编码                  if(err == wsaewouldblock)           // 接收数据缓冲区暂无数据                  {                      sleep(100);                      printf("waiting back msg !n");                      continue;                  }                  else if(err == wsaetimedout || err == wsaenetdown)                  {                      printf("recv failed !n");                         closesocket(shost);                         wsacleanup();                         return -1;                  }                  break;              }                 break;          }             //zeromemory(buf,buf_size);                     // 清空接收数据的缓冲区          //retval = recv(shost,buf,sizeof(buf)+1,0);   // 接收服务器回传的数据               printf("recv from server: %sn",buf);             // 如果收到quit,则退出          if(strcmp(buf, "quit") == 0)          {              printf("quit!n");              break;          }      }      // 释放资源         closesocket(shost);         wsacleanup();         // 暂停,按任意键继续      system("pause");      return 0;    }  

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/c-cdevelopment/607831.html

(0)
上一篇 2021年5月14日
下一篇 2021年5月14日

精彩推荐