zoukankan      html  css  js  c++  java
  • Winsock 示例

    #include "stdafx.h"
    #include <Windows.h>
    #include <iostream>
    
    #pragma comment(lib,"ws2_32.lib")
    
    using namespace std;
    
    int main(int argc, char* argv[]){
        WSADATA wsaData;
        int err;
        err=WSAStartup(MAKEWORD(2,2),&wsaData);//如果这里是(1,1)则下面第一个输出为257,即0x0101
        if(err==0){
            cout<<"success"<<endl;
        }
         cout<<"Windows Sockets DLL期望调用者使用的Windows Sockets规范的版本: "<<wsaData.wVersion<<endl;//0x0202  
       
    cout<<"这个DLL能够支持的Windows Sockets规范的最高版本.通常它与wVersion相同: "<<wsaData.wHighVersion<<endl;//0x0202 
        //So, to initialise an application to support Winsock 1.1 you'd use a value of 257 ( 0000000100000001 binary).  For Winsock 2.2 you'd use 514 ( 0000001000000010 binary).    
        system("pause");
        return 0;
    } 

     网络编程框架:

    写一个网络应用程序分为两个方面:服务器程序和客户端程序,大家可以在一个solution中建立srv和client两个projects。
     
    首先回忆一下程序框架
     
    #include<winsock2.h> // 头文件 
    #pragma comment(lib, "ws2_32.lib") // 库文件加载 
    void main(void) 

    WSADATA wsaData; // WSADATA 结构体主要包含了系统所支持的Winsock版本信息 
     
    // 初始化Winsock 2.2。使用WSAStartup函数,第一个参数是所要用的Winsock版本号 
    // 第二个参数就是WSADATA结构体的指针。如果初始化成功则返回0 
    // 要注意任何WinsockAPI函数都必须在初始化后使用,包括错误检查函数 
    // WSAGetLastError (用于查看出错详细信息) 

     
    if( WSAStartup( MAKEWORD(2,2), &wsaData) != 0 ) 

    printf( "WSAStartup 无法初始化!"); 
    return; 

     
    // winsock 应用代码 
     
    // 最后应该做一些清除工作 
    if( WSACleanup() == SOCKET_ERROR ) 
    printf( "WSACleanup 出错!"); 
     
    }
    现在我们的任务是填写红色的部分,即winsock应用代码
     
    1. 简单TCP/IP
     
    思路: 
    [服务器程序]
     
    建立socket -----> 绑定bind------>监听listen------>接受accept------>发送和接收send 和 recv------>关闭closesocket
     
    [客户端程序]

     
    建立socket -----> 连接connect------>发送和接收send 和 recv------>关闭closesocket
     
    代码:
     
    [服务器程序]
     
    /*使用IP地址家族就必须要用AF_INET,由于我们要建立可靠的传送,因此我们选择SOCK_STREAM,基于数据流的传送,最后一个参数表示使用TCP协议,实际上这个参数可以设置为0,让程序自己根据情况判断填写*/

    SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP ) 
     
    /*绑定的意思是把socket绑定到IP地址上,所以我们需要一个SOCKADDR结构来存放IP地址信息,这里为了方便填写可以使用SOCKADDR_IN结构,这个结构的大小和SOCKADDR一样,可以强制类型转换到SOCKADDR类型,填写给bind函数的参数。这里要注意的是要把IP地址和端口号转化为网络存储顺序,即高位存放在低字节内存中,可以用htonl和htons函数转化*/

    SOCKADDR_IN addrSrv;
    addrSrv.sin_family = AF_INET;
    addrSrv.sin_addr.s_addr = htonl( INADDR_ANY); // INADR_ANY表示使用默认IP地址 
    addrSrv.sin_port = htons( 27015 );//尽量不要使用在1024以下的端口 
     
    bind( sockSrv, (SOCKADDR*)&addrSrv, sizeof(addrSrv) );
     
    /*监听,第二个参数表示等待序列的最大个数,就好比最多只能容纳5个人排队,第六个就被拒绝排队了。*/
    listen( sockSrv, 5 );
     
    /* 接受, 就好比处理房间中第一个人的事务,那么这个队列就空出一个人的位置,其他人还可以来排队。这里通过accept函数可以返回一个表示连接进来的客户的socket,并且通过传递参数可以知道客户端的IP地址信息*/
     
    SOCKADDR_IN addrClient;
    int len = sizeof(addrClient);
     
    // 循环接受客户,这里没有写退出条件,实际上退出条件可以来自判断所读入的信息 
    while(1)
    {
    SOCKET sockClient = accept( sockSrv, (SOCKADDR*)&adrClient, &len );
     
    // 发送和接收数据 char sendbuf[32] = "Server: Sending Data.";
    char recvbuf[32] = "";
     
    // recv 和 send的参数都是 socket,buffer,buffer的大小以及一个flag,具体可参考MSDN 
    bytesRecv = recv( sockClient, recvbuf, 32, 0 ); 
    printf( "Recv: %s ", recvbuf );
     
    bytesSent = send( sockClient, sendbuf, strlen(sendbuf), 0 );
     
    }
     
    // 关闭socket 
    closesocket(sockClient);
    closesocket(sockSrv);

    完整代码:

    #include "stdafx.h"
    #include<winsock2.h>
    #include<iostream>
    #pragma comment(lib,"ws2_32.lib")
    
    using namespace std;
    int main(){
        WSADATA wsaData;
        SOCKET s;
        int errStartup,errBind;
        errStartup=WSAStartup(MAKEWORD(2,2),&wsaData);
        if(errStartup!=0){
            cout<<"初始化失败"<<endl;
            return -1;
        }

       if (LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
       {
          MessageBox(NULL,_T("error"),NULL,NULL);
          WSACleanup();
          return -4;
       }

    
        s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        if(s==INVALID_SOCKET){
            cout<<"创建socket失败"<<endl;
         WSACleanup();
    return -2; } SOCKADDR_IN addr; memset(&addr,0,sizeof(addr)); addr.sin_family=AF_INET; addr.sin_addr.S_un.S_addr=htonl(INADDR_ANY); addr.sin_port=htons(30000); errBind= bind(s,(SOCKADDR*)&addr,sizeof(addr)); if(errBind!=0){ cout<<"bind failed!"<<endl;

          closesocket(s);
          WSACleanup();

        return -3;
        }
        listen(s,3);
    
        SOCKADDR_IN addrClient;
        int len=sizeof(addrClient);
        
        while (true)
        {
            SOCKET sockClient=accept(s,(SOCKADDR*)&addrClient,&len);
             char *sendBuf="Server:sending data.";
             char recBuf[512]={0};
            memset(recBuf,0,sizeof(recBuf));
            int sendNum= send(sockClient,sendBuf,strlen(sendBuf)+1,0);
             cout<<sendNum<<endl;
             int recNum= recv(sockClient,recBuf,512,0);
            cout<<recBuf<<" from "<<inet_ntoa(addrClient.sin_addr)<<endl;
             
    
            shutdown(sockClient,SD_BOTH);
            closesocket(sockClient);
        }
        
        closesocket(s);
        WSACleanup();
        system("pause");
        return 0;
    }


     
    [客户端程序]
     

    // client.cpp : 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include <WinSock2.h>
    #include <iostream>
    using namespace std;
    
    #pragma comment(lib,"ws2_32.lib")
    
     
    int _tmain(int argc, TCHAR *argv[]) 
    { 
       WSADATA wsaData;
       SOCKADDR_IN s;
       int conerr;
        WSAStartup(MAKEWORD(1,1),&wsaData);
    
        SOCKET clientSock=socket(AF_INET,SOCK_STREAM,0);
        memset(&s,0,sizeof(s));
        s.sin_family=AF_INET;
        s.sin_addr.S_un.S_addr=inet_addr("172.18.4.161");
        s.sin_port=htons(30000);
        conerr= connect(clientSock,(SOCKADDR*)&s,sizeof(s));
        if(conerr!=0){
            cout<<"connect failed:"<<conerr<<endl;
    
        }
         char *sendBuf="Client:sending data.";
         char recBuf[512]={0};
         memset(recBuf,0,sizeof(recBuf));
            
    
             int recNum= recv(clientSock,recBuf,512,0);
            cout<<recBuf<<endl;
             int sendNum= send(clientSock,sendBuf,strlen(sendBuf)+1,0);
             cout<<sendNum<<endl;
    
        
    
        system("pause");
       return 0; 
    }

    不同机器之间通信切记把防火墙关掉!!!从控制面板中关闭,不要直接关服务
     
     
     
    2. 简单UDP/IP
     
    思路: 
     
    [服务器程序]
     
    建立socket -----> 绑定bind------>发送和接收sendto 和 recvfrom------>关闭closesocket
     
    [客户端程序]
     
    建立socket -----> 发送和接收send 和 recv------>关闭closesocket
     
    UDP的实现更加简单,服务器只要绑定就可以发送接收信息,而客户端只要有socket就可以了。具体的实现代码可以参考MSDN中的例子。

    要注意的是
    TCP中用SOCK_STREAM 建立socket,并且使用send和recv函数发送接收信息。
    UDP中用SOCK_DGRAM 建立socket,并且使用sendto和recvfrom来发送和接收信息。sendto 比send多几个参数,主要是对方的IP地址信息,recvfrom也是一样比recv多几个参数。

  • 相关阅读:
    PAT1066(AVL树)
    判断是对象,还是数组对象
    electron打包成.exe后限制只启动一个应用
    electron启动出现短暂的白屏
    js sort方法根据数组中对象的某一个属性值进行排序
    VUE DIV模拟input框的基本处理
    vue 设置 input 为不可以编辑
    VUE实现限制输入框最多输入15个中文,或者30个英文
    electron 点击事件无效
    electron监听系统托盘,electron是否最小化到系统托盘
  • 原文地址:https://www.cnblogs.com/duyy/p/3740216.html
Copyright © 2011-2022 走看看