Windows 网络编程(7)

 1>Winsock初始化 (有连接)

        a>加载Winsock DLL
             int   WSAStartup  ( WORD                wVersionRepuested,   //指定准备加载的版本,
                                 LpWSADATA      lpWSAData
                                            );
            说明: 版本由宏MAKEWORD(X,Y)获得,X是高位字节(副版本),Y是低位字节(主版本),
                     LPWSADATA  结构:
                      typedef   struct   WSAData
                      {
                            WORD              wVersion,            //准备使用的Winsock版本
                            WORD              wHighVersion,        //存放现有的最高版本
                            char              szDescription[WSADESCRIPTION_LEN + 1],    //无用
                            char              szSystemStatus[WSASYS_STATUS_LEN + 1],   //无用
                            unsigned short    iMaxSockets,         //不要使用
                            unsigned  short   iMaxUdpDg,           //不要使用
                            char      FAR  *  lpVendorInfo,        //不用
                      }WSADATA,FAR* LPWSADATA;
         b>错语检查和控制
              int  WSAGetLastError (void);
         c>面向连接的协议
             i>bind
               int  bind (SOCKET                           s,
                          const struct sockaddr  FAR  *  name,
                          int                              namelen
                          );
                   例:
                            SOCKET               s;
                            struct  sockaddr_in  tcpaddr;
                            int                  port=5150;
                            s = socket( AF_INET,SOCK_STEAM,IPPROTO_TCP);
                            tcpaddr.sin_family  = AF_INET;
                            tcpaddr.sin_port = htons(port);
                            tcpaddr.sin_addr.s_addr=htonl(INADDR_ANY);
                            bind(  s, (SOCKADDR * ) &tcpaddr, sizeof(tcpaddr) );
            ii>listen
                 int listen ( SOCKET  s,
                              int     backlog   //指定正在等待连接的最大队列长度
                            );
           iii>accept  和  WSAAccept
                 SOCKET   accept  (  SOCKET                 s,         //处在监听模式的套接字
                                     struct sockaddr  FAR * addr,      //SOCKADDR_IN结构的地址,返回后包含请求方IP
                                     int    FAR *           addrlen    //SOCKADDR_IN结构的长度
                                  );    
//成功后,会返回一个新套接字,与客户机沟通以后就用此新套接字
                 SOCKET   WSAAccept ( SOCKET s,
                                      struct sockaddr FAR * addr,
                                      LPINT addrlen,
                                      LPCONDITIONPROC lpfnCondition,  //函数指针(如下),根据客户请求来调用,它决定接受请求
                                      DWORD dwCallbackData);
                 说明: int CALLBACK ConditionFunc( LPWSABUF lpCallerID,  //值参数,包含连接实体的地址,
                                                   LPWSABUY lpCallerData,//随连接请求发过来的任何连接数据
                                                   LPQOS    lpSQOS,
                                                   LPQOS    lpGQOS,
                                                   LPWSABUF lpCalleeID,  //包含本地IP
                                                   LPWSABUF lpCalleeData,//对lpCallerData的补充
                                                   GROUP  FAR * g,
                                                   DWORD dwCallbackData
                                                 );

                      typedef  struct  __WSABUF
                           {
                              u_long   len;  //其值要么由buf指向的缓冲区长度,要么指定包含在缓冲区buf中的数据量
                              char FAR * buf;
                           } WSABUF,FAR * LPWSABUF;

                       说明:对 lpCallerID来说,buf指向一个地址结构如SOCKADDR类型,所以包含了客户机IP                      
         d>connect 和 WSAConnect 函数
           int connect (SOCKET s,const struct sockaddr FAR * name,int namelen)
           int WSAConnect ( SOCKET s,const struct sockaddr FAR * name,int namelen,
                            LPWSABUF lpCallerData,   //收发请求接接时的数据,包含客户机向服务器发的请求连接的数据
                            LpWSABUF lpCalleeData,   //收发请求连接时的数据,包含服务器向客户机返回的建立连接的数据
                            LPQOS    lpSQOS,
                            LPQOS    lpGQOS);
          切记,所有关系到收发数据的缓冲都属于char类型,无Unicode版本,使用Unicode时,把字符串当作char * 或造型为char * 发送
               利用字符串长度函数告诉Winsock API函数收发的数据有多少字符时,必须将这个值乘以2,另外一种就是在将字符串数据投给
               Winsock API 函数之前,用WideCharToMultiByte把UNICODE转换成ASCII码
         e>send 和 WSASend
           int send (SOCKET s,
                     const char FAR * buf,
                     int len,
                     int flags);
//若成功,返回发送的字节数
           int WSASend (SOCKET      s,
                        LPWSABUF    lpBuffers, //指向一个或多个WSABUF结构的指针,
                        DWORD       dwBufferCount,   //准备投递的结构数
                        LPDWORD     lpNumberOfBytesSent,//指向DWORD(WSASend调用返回的)指针,其中包含总发送数,
                        DWORD       dwFlags,
                        LPWSAOVERLAPPED  lpOverlapped,   //用于重叠I/O
                        LPWSAOVERLappED_COMPLETION_ROUTINE  lpCompletROUTINE  //用于重叠I/O
                       );
        f>recv 和  WSARecv
          int recv( SOCKET  s,
                    char FAR * buf, //即将收到的字符缓冲,
                    int len,    //准备接收的字节数或buf缓冲的长度,
                    int flags   //0,或MSG_PEEK,MSG_OOB 或是它们的接位运算,MSG_PEEK 使数据复制到所提供的接收端缓冲,但系统还有
                  );
          int WSARecv ( SOCKET s,
                        LPWSABUF    lpBuffers,     //WSABUF 结构组成的数组
                        DWORD       dwBufferCount, //前一个数组中WSABUF结构的数目
                        LPDWORD     lpNumberOfBytesRecvd,  //指向执行这个函数调用所收到的字节数
                        lpDWORD     lpFlags,
                        LPWSAOVERLAPPED  lpOverlapped,
                        LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionROUTINE
                      );
       g>保证流式套接字所有的数据都发送出去,代码如下:
           char sendbuff[2048];
           int  nBytes = 2048,
                nLeft,
                idx;
           nLeft = nBytes;
           idx = 0;
           while (nLeft>0)
           {
             ret=send(s,&sendbuff[idx],nLeft,0);
             if (red==SOCKET_ERROR)
             { //Error}
             nLeft-=ret;
             idx +=ret;
           }
         h>中断连接
           int shutdown (SOCKET   s,  //
                            int   how  //可以是 SD_RECEIVE,SD_SEND或SD_BOTH,即不允许再调用相关函数
                        );
           int closesocket (SOCKET s);
2>例子:
        a>回应服务器代码
          #include <winsock2.h>
          #include <stdio.h>
          #define DEFAULT_PORT     5150
          #define DERAULT_bUFFER   4096

          int    port         = DEFAULT_PORT;
          BOOL   bInterface   = FALSE,
                 bRecvOnly    =FALSE;
          char   szAddress[128];
         
          void  usage()
          {
             printf ("usage: server [-p:x] [-i:IP] [-o] /n/n");
             printf ("       -p:x     port number to listen on/n");
             printf ("       -i:str  Interface to listen on/n");
             printf ("       -o      Don't echo the data back/n/n");
             ExitProcess(1);
          }
          void ValidateArgs ( int argc,char ** argv)
          {
             int i;
             for (i=1;i<argc;i++)
             {
                if ((argv[i][0]=='-')||(argv[i][0]=='/'))
                {
                   switch (tolower(argv[i][1]))
                   {
                      case 'p':
                         iPort = atoi(&argv[i][3]);
                         break;
                      case 'i':
                         bInterface = TRUE;
                         if (strlen(argv[i]>3)
                            strcpy (szAddress,&argv[i][3]);
                        break;
                      case 'o':
                         bRecvOnly = TRUE;
                         break;
                      default :
                         usage();
                         break;
                   }
                }
             }
          }

          //  线程
          DWORD  WINAPI   ClientThread ( LPVOID  lpParam )
          {
             SOCKET  sock=( SOCKET ) lpParam;
             char    szBuff[DEFAULT_BUFFER];
             int     ret,
                     nLeft,
                     idx;
           
             while (1)
             {
                ret = recv(sock,szBuff,DEFAULT_BUFFER,0);
                if (ret==0)  //正常返回(没有接收到数据)
                   break;
                else if (ret==SOCKET_ERROR)
                {
                   printf("recv() failed: %d/n",WSAGetLastError());
                   break;
                }
                szBuff[ret] = '/0';
                printf("RECV: '%s'/n",szBuff);
                //如果定义了回复
                if (! bRecvOnly)
                {
                   nLeft = ret;
                   idx = 0;
                   while (nLeft > 0)     //确保发送了所有的数据
                   {
                      ret = send (sock,&szBuff[idx],nLeft,0);
                      if (ret==0)
                         break;
                      else if (ret==SOCKET_ERROr)
                      {
                         printf ("send() failed: %d/n",WSAGetLastError());
                         break;
                      }
                      nLeft -= ret;
                      idx += ret; 
                   }
                }
             }
             return 0;
          }
          //主函数
          int  main(int argc,char ** argv)
          {
             WSADATA              wsd;
             SOCKET               sListen,
                                  sClient;
             int                  iAddrSize;
             HANDLE               hThread;
             DWORD                dwThreadID;
             struct sockaddr_in   local,
                                  client;
            
             ValidateArgs (argc,argv);
             if (WSAStartup(MAKEWORD(2,2),&wsd)!=0)
             {
                printf ("Failed to load Winsock!/n");
                return 1;
             }
            
             slisten = socket (AF_INET,SOCK_STREAM,IPPROTO_IP);
             if (sListen==SOCKET_ERROR)
             {
                printf (" socket() failed:%d/n",WSAGetLastError());
                return 1;
             }
            
             if (bInterface)
             {
                local.sin_addr.s_addr = inet_addr(szAddress);
                if (local.sin_addr.s_addr==INADDR_NONE)
                { usage();}
             }
             else
                local.sin_addr.s_addr = htonl(INADDR_ANY);
             local.sin_family = AF_INET;
             local.sin_port   = htons(iPort);

             if (bind(sListen,(struct sockaddr *)&local,sizeof(local))==SOCKET_ERROR)
             {
                printf ("bind() failed:%d/n",WSAGetLastError());
                return 1;
             }
             listen (sListen,8);
            
             while (1)
             {
                iAddrSize = sizeof(client);
                sClient = accept (sListen,(struct sockaddr *)&client,&iAddrSize);
                if (sClient == INVALID_SOCKET)
                {
                   printf ("accept() failed: %d/n",WSAGetLastError());
                   break;
                }
                printf("Accepted client: %s:%d/n",inet_ntoa(client.sin_addr),ngohs(client.sin_port));
 
                hThread = CreateThread (NULL,0,ClientThread,(LPVOID)sClient,0,&dwThreadID);
                if (hThread ==NULL)
                {
                   printf("CreatThread() failed:%d/n",GetLastError());
                   break;
                }
                CloseHandle(hThread);
             }
             closesocket(sListen);
            
             WSACleanup();
             return 0;
          }
   ///      

       b>客户机代码
          #include <winsock2.h>
          #include <stdio.h>
          #include <stdlib.h>
 
          #define  DEFAULT_COUNT     20
          #define  DEFAULT_PORT      5150
          #define  DEFAULT_BUFFER    2048
          #define  DEFAULT_MESSAGE   "This is a test of the emergency / broadcasting system"

          char     szServer[128],
                   szMessage[1024];   //向服务器发送的信息
          int      iPort     = DEFAULT_PORT;
          DWORD    dwCount   = DEFAULT_COUNt;
          BOOL     bSendOnly = FALSE;   //只发不收标志
         
          void  usage()
          {
             printf ("usage: client [-p:x] [-s:IP] [-n:x] [-o] /n/n");
             printf ("       -p:x     Remote port to send to/n");
             printf ("       -s:IP    Server's IP address or host name/n");
             printf ("       -n:x     Number of timer to send message/n");
             printf ("       -o       Send message only;Don't receive/n");
             ExitProcess(1);
          }
         
          void ValidateArgs ( int argc,char ** argv)
          {
             int i;
             for (i=1;i<argc;i++)
             {
                if ((argv[i][0]=='-')||(argv[i][0]=='/'))
                {
                   switch (tolower(argv[i][1]))
                   {
                      case 'p':
                         if (strlen(argv[i])>3)
                            iPort = atoi(&argv[i][3]);
                         break;
                      case 's':
                         if (strlen(argv[i]>3)
                            dwCount = atoi(&argv[1][3]);
                        break;
                      case 'o':
                         bSendOnly = TRUE;
                         break;
                      default :
                         usage();
                         break;
                   }
                }
             }
          }
         
          int main( int argc,char **argv)
          {
             WSADATA     wsd;
             SOCKET      sClient;
             char        szBuffer[DEFAULT_BUFFER];
             int         ret,
                         i;
             struct sockaddr_in   server;
             struct hostent       *host = NULL;
            
             ValidateArgs( argc,argv);
             if (WSAStartup(MAKEWORD(2,2),&wsd)!=0)
             {
                 printf ("Failed to load Winsock librarv!/n");
                 return i;
             }
             strcpy( szMessage,DEFAULT_MESSAGE);

             sClient = socket (AF_INET,SOCk_STREAM,IPPROTO_TCP);
             if (sClient == INVALID_SOCKET)
             {
                 printf ("socket() failed:%d/n",GETLastError());
                 return 1;
             }
             server.sin_family       = AF_INET;
             server.sin_port         = htons(iPort);
             server.sin_addr.s_addr  = inet_addr(szServer);
            
             if(server.sin_addr.s_addr == INADDR_NONE)
             {
                 host = gethostbyname (szServer);
                 if (host==NULL)
                 {
                    printf ("Unable to resolve server: %s/n",szServer);
                    return 1;
                 }
                 CopyMemory (&server.sin_addr,host->h_addr_list[0],host->h_length);
             }
             if (connect (sClient,(struct sockaddr * )&server,sizeof(server)) == SOCKET_ERROR)
             {
                //Error
             }
            
             for (i=0;i<dwCount;i++)
             {
                 ret = send (sClient,szMessage,strlen(szMessage),0);
                 if (ret==0) { break;}
                 else if (ret ==SOCKET_ERROR)
                 {
                     //Error
                 }
                 printf ("Send %d bytes/n",ret);
                 if (!bSendOnly)
                 {
                     ret =recv (sClient,szBuffer,DefAULT_BUFFER,0);
                     if (ret ==0)  {break;}
                     else if (ret ==SOCKET_ERROR)  {//Error}
                 }
                 szBuffer[ret]='/0';
                 printf ("RECV [%d bytes]:'%s'/n",ret,szBuffer);
             }
             closesocket (sClient);
            
             WSACleanup();
             return 0;
          }

3.无连接协议
    i>无需listen和accept,只接接收和发送
      int recvfrom (SOCKET s,
                    char  FAR* buf,
                    int    len,
                    int    flags,
                    struct sockaddr FAR * from,
                    int FAR * fromlen
                   );
      int WSARecvFrom (SOCKET s,
                       LPWSABUF lpBuffers,    //缓冲数组指针
                       DWORD    dwBufferCount,   // 指定包含的缓冲数
                       LPDWORD  lpNumberOfBytesRecvd,   //返回读取的字节总数
                       LPDWORD  lpFlags,
                       struct  sockaddr FAR * lpFrom,    //包含发送方的IP
                       LPINT lpFromlen,                  //SOCKADDR结构的长充
                       LPWSAOVERLAPPED lpOverlapped,
                       LPWSAOVERLAPPED_COMPLETION_ROUTINE  lpCompletionROUTINE
                      );
      int sendto( SOCKET s,
                  const char FAR* buf,
                  int len,
                  int flags,
                  const struct sockaddr FAR * to,
                  int tolen
                )
      int WSASendTo (SOCKET s,
                     LPWSABUF  lpBuffers,
                     DWORD dwBufferCount,
                     LPDWORD lpNumberOfBytesSent,   //真正发送的字节数
                     DWORD dwFlags,
                     const struct sockaddr FAR * lpTo,
                     int itolen,
                     LPWSAOVERLAPPED lpOverlapped,
                     LPWSAOVERLAPPED_COMpLETION_ROUTINE lpCompletionROUTINE
                    )
4>无连接的例
     i>接收端 
      #include <winsock2.h>
      #include <stdio.h>
      #include <stdlib.h>

      #define  DEFAULT_PORT                   5150
      #define  DEFAULT_COUNT                  25
      #define  DEFAULT_BUFFER_LENGTH          4096
     
      int     iPort     =DEFAULT_PORT;
      DWORD   dwCount   =DEFAULT_COUNT,
              dwLength  =DEFAULT_BUFFER_LENGTH;
      BOOL    bInterface =FALSE;

      char    szInterface[32];

      void usage()
      {
          printf ("usage:sender [-p:int] [-i:IP] [-n:x] [-b:x]/n/n");
          printf ("             -p:int  Local prot/n");
          printf ("             -i:IP   Local IP address to listen on/n");
          printf ("             -n:x    Number of times to send message/n");
          printf ("             -b:x    Size of buffer jto send/n/n");
          ExitProcess (1);
      }
     
      void ValidateArgs(int argc,char** argv)
      {
          int              i;
         
          for (i=1;i<argc;i++)
          {
             if ((argv[i][0]=='-')||(argv[i][0])=='/')
             {
                switch (tolower(argv[i][1]))
                {
                   case 'p':          //Local port
                      if (strlen(argv[i])>3)
                         iPort=atoi(&argv[i][3]);
                      break;
                   case 'n':
                      if(strlen(argv[i])>3)
                         dwLength = atoi(&argv[i][3]);
                      break;
                   case 'i':
                      if (strlen(argv[i])>3)
                      {
                          bInterface = TRUE;
                          strcpy(szInterface,&argv[i][3]);
                      }
                      break;
                   default:
                      usage();
                      break;
                }
             }
          }
      }

      int  main (int argc,char ** argv)
      {
          WSADATA             wsd;
          SOCKET              s;
          char                *recvbuf = NULL;
          int                 ret,
                              i;
          DWORD               dwSenderSize;
          SOCKADDR_IN         sender,
                              local;

          ValidateArgx(argc,argv);
          if (WSAStartup (MAKEWORD(2,2),&wsd)!=0)
          {
             //Error
          }
         
          s = socket(AF_INET,SOCK_DGRAM,0);
          if (s==INVALID_SOCKET)
          {  //Error  }
         
          local.sin_family = AF_INET;
          local.sin_port   = htons((short)iPort);
          if (bInterface)
             local.sin_addr.s_addr  = inet_addr(szInterface);
          else
             local.sin_addr.s_addr  = htonl(INADDR_ANY);
         
          if (bind(s,(SOCKADDR *)&local,sizeof(local))==SOCKET_ERROR)
          {  //Error  }
         
          recvbuf = GlobalAlloc(GMEM_FIXED,dwLength);
          if (!recvbuf)
          {   //Error  }
         
          for (i=0,i<dwCount;i++)
          {
              dwSenderSize = sizeof(sender);
              ret = recvfrom(s,recvbuf,dwLength,0,(SOCKADDR*)&sender,&dwSenderSize);
              if (ret == SOCKET_ERROR)  {  //Error  }
              else if (ret==0)  {break;}
              else
              {
                 recvbuf[ret]='/0';
                 printf("[%s] sent me: '%s'/n",inet_ntoa(sender.sin_addr),recvbuf);
              }
          }
          closesocket(s);
          GlobalFree(recvbuf);
          WSACleanup();
          return 0; 
      }

     ii>无连接的  发送端
      #include  <winsock2.h>
      #include  <stdio.h>
      #include  <stdlib.h>

      #define   DEFAULT_PORT            5150
      #define   DEFAULT_COUNT           25
      #define   DEFAULT_CHAR            'a'
      #define   DEFAULT_BUFFER_LENGTH   64

      BOOL      bConnect = FALSE;
      int       iPort    = DEFAULT_PORT;
      char      cChar    = DEFAULT_CHAR;
      DWORD     dwCount  = DEFAULT_COUNT;
                dwLength = DEFAULT_BUFFER_LENGTH;
      char      szRecipient[128];

      void usage()
      {
          printf("");
          printf("");
          printf("");
          printf("");
          printf("");
          printf("");
          printf("");
          ExitProcess(1);
      }

      void ValidateArgs(int argc,char ** argv)
      {
          int            i;
          for(i=1;i<argc;i++)
          {
              if((argv[i][0]=='-')||(argv[i][0]=='/'))
              {
                 switch (tolower(argv[i][1]))
                 {
                    case 'p':
                       if(strlen(argv[i])>3)
                          iPort = atoi(&argv[i][3]);
                       break;
                    case 'r':
                       if(strlen(argv[i])>3)
                          strcpy(szRecipient,&argv[i][3]);
                       break;
                    case 'c':
                       if(strlen(argv[i])>3)
                          dwCount = atoi(&argv[i][3]);
                       break;
                    case 'b':
                       if(strlen(argv[i])>3)
                          dwLength = atoi(&argv[i][3])
                       break;
                    default:
                       usage();
                       break;
                 }
              }
          }
      }

      int main(int argc,char** argv)
      {
          WSADATA               wsd;
          SOCKET                s;
          char                  *sendbuf = NULL;
          int                   ret,
                                i;
          SOCKADDR_IN           recipient;
         
          validateArgs(argc,argv);
          if (WSAStarup(MAKEWORD(2,2),&wsd)!=0)
          {  //Error  }
         
          s = socket(AF_INET,SOCK_DGRAM,0);
          if(s==INVALID_SOCKET)    {  //Error }
         
          recipient.sin_family = AF_INET;
          recipient.sin_port   = htons((short)iProt);
          if ((recipient.sin_addr.s_addr =  inet_addr(szRecipient))==INADDR_NONE)
          {
             struct hostent *hosts=NULL;

             host = gethostbyname(szRecipient);
             if(host)
                CopyMemory(&recipient.sin_addr,host->h_addr_list[0],host->h_length);
             else
             {
                printf("gethostbyname() failed: %d/n",WSAGetLastError());
                WSAClearup();
                return 1;
             }
           }

           sendbuf = GlobalAlloc(GMEM_FIXED,dwLength);
           if(!sendbuf)
           {  //Error  }
           memset(sendbuf,cChar,dwLength);
          
           if (bConnect)
           {
               if(connect(s,(SOCKADDR*)&recipient,sizeof(recipient))==SOCKET_ERROR)
               {
                  printf("");
                  GlobalFree(sendbuf);
                  WSACleanup();
                  return 1;
               }
               for(i=0;i<dwCount;i++)
               {
                 ret = send(s,sendbuf,dwLength,0);
                 if (ret=SOCKET_ERROR) 
                    {//  Error  }
                 else if (ret==0)
                    break;
               }
           }
           else
           {
               for(i=0;i<dwCount;i++)
               {
                   ret = sendto(s,sendbuf,dwLength,0,(SOCKADDR*)&recipient,sizeof(recipient));
                   if (ret == SOCKET_ERROR)
                   {   //Error  }
                   else if (ret==0)
                      break;
               }
           }
           closesocket(s);
           GlobalFree(sendbuf);
           WSACleanup();
           return 0;
      }
5> 其它 API 函数

      i>  int getpeername(SOCKET  s,     //准备连接的套接字
                          struct sockaddr FAR* name,
                          int  FAR* namelen
                          );//获得通信方的套接字地址信息,对数据报来说,是连接调用的地址,而不是sendto地址 
      ii> int getsockname(SOCKET  s,
                          struct  sockaddr FAR* name,
                          int FAR* namelen
                         ); 
//返回指定套接字的本地接口信息

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值