zoukankan      html  css  js  c++  java
  • C/S模型之UDP协议

    说明:
    利用UDP协议,创建一个服务器和一个客户端。两者间进行通信。
    由客户端进行输入内容,而服务器将接受的内容进行再一次返回,并显示在服务端。

    // UDP_Seversock.cpp : 定义控制台应用程序的入口点。
    
    #include "stdafx.h"
    #include <WinSock2.h>
    #include <Windows.h>
    #pragma comment (lib,"WS2_32.lib")
    
    //服务器端
    int _tmain(int argc, _TCHAR* argv[])
    {
        //检测版本
        WSADATA wsaData;
        int nErr = WSAStartup(MAKEWORD(2, 2), &wsaData);
        if (nErr != 0)
        {
            printf("WSAStartup Failed %d", GetLastError());
            return -1;
        }
    
        if (HIBYTE(wsaData.wVersion != 2 || wsaData.wVersion != 2))
        {
            printf("WinSock2 version not is WS2_32");
            WSACleanup();
            return -1;
        }
    
        //开始
        SOCKET sockSever = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    
        //设置端口号和IP地址,INADDR_ANY是任意IP地址
        SOCKADDR_IN sockSeverAddr;
        sockSeverAddr.sin_family = AF_INET;
        sockSeverAddr.sin_port = htons(10086);
        //sockSeverAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
        sockSeverAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    
        //将socket进行绑定
        int nBindErr = bind(sockSever, (sockaddr*)&sockSeverAddr, sizeof(SOCKADDR_IN));
        if (nBindErr == SOCKET_ERROR)
        {
            printf("bind Error!");
            closesocket(sockSever);
            WSACleanup();
        }
        printf("connect sucess!
    ");
        
        SOCKADDR_IN SenderAddr;
        int SenderAddrSize = sizeof (SenderAddr);
    
        char pRecvBuf[MAXBYTE] = { 0 };
        char pPrintBuf[MAXBYTE] = { 0 };
    
        while (1)
        {
            int nResult = recvfrom(sockSever, pRecvBuf, MAXBYTE, 0, (SOCKADDR *)&SenderAddr, &SenderAddrSize);
    
            if (nResult == SOCKET_ERROR)
            {
                printf("recvfrom failed with error ");
            }
    
            //重置,将IP地址和端口号,内容存放在pPrintBuf中
            sprintf_s(pPrintBuf, "%s(%d):%s
    ", inet_ntoa(sockSeverAddr.sin_addr), ntohs(sockSeverAddr.sin_port), pRecvBuf);
    
            //输出在窗口
            printf("%s
    ", pPrintBuf);
    
            //客户端请求退出
            if (strcmp(pRecvBuf, "Q") == 0)
            {
                break;
            }
    
            int nSendResult = sendto(sockSever, pRecvBuf, MAXBYTE, 0, (sockaddr*)&SenderAddr, SenderAddrSize);
            if (nSendResult == SOCKET_ERROR)
            {
                printf("sendto  Error!");
                break;
            }
        }
    
        closesocket(sockSever);
        WSACleanup();
        return 0;
    }
    #include "stdafx.h"
    #include <WinSock2.h>
    #include <Windows.h>
    #pragma comment(lib,"WS2_32.lib")
    
    //客户端
    int _tmain(int argc, _TCHAR* argv[])
    {
        //socket版本检测
        WSAData wsaData;
        int nErr=WSAStartup(MAKEWORD(2, 2), &wsaData); 
        if (nErr != 0)
        {
            printf("WSAStartup Failed %d", GetLastError());
            return -1;
        }
        if (HIBYTE(wsaData.wVersion) != 2 || LOBYTE(wsaData.wVersion) != 2)
        {
            printf("WinSock2 version not is WS2_32");
            WSACleanup();
                return -1;
        }
    
        //程序开始
        SOCKET sockClient = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    
        //设定端口和IP地址,127.0.0.1是本机回环地址
        SOCKADDR_IN sockAddr;
        sockAddr.sin_family = AF_INET;
        sockAddr.sin_port = htons(10086);
        sockAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
        int RecvAddrSize = sizeof (SOCKADDR_IN);
    
        //int nBindErr=bind(sockClient, (sockaddr*)&sockAddr, sizeof(SOCKADDR_IN));
        //if (nBindErr == SOCKET_ERROR)
        //{
        //    printf("bind Error!");
        //    closesocket(sockClient);
        //    WSACleanup();
        //    return -1;
        //}
    
        printf("connect sucess!
    ");
    
        char pSendBuf[MAXBYTE] = { 0 };        //发送服务器的内容
        char pRecvBuf[MAXBYTE] = { 0 };        //接受服务器返回的内容
    
        while (1)
        {
            gets_s(pSendBuf);
    
            //发送给服务器
            int nResule = sendto(sockClient, pSendBuf, MAXBYTE, 0, (SOCKADDR *)& sockAddr, RecvAddrSize);
            if (nResule == SOCKET_ERROR)
            {
                printf("sendto  Error!");
            }
    
            //接受服务器返回的内容
            int nRecvErr = recvfrom(sockClient, pRecvBuf, MAXBYTE, 0, (SOCKADDR *)& sockAddr, &RecvAddrSize);
            if (nRecvErr == SOCKET_ERROR)
            {
                break;
            }
    
            //服务器返回内容
            printf("return from sever:%s
    ", pRecvBuf);
    
        }
        closesocket(sockClient);
        WSACleanup();
        return 0;
    }

    注意点;
    问题:为什么UDP协议的客户端的socket不需要绑定IP地址和端口号?
    解析; 
    书上都是这么说的,UDP客户端不用绑定IP和端口,操作系统会给它自动分配端口。。。。

    但是虽然没有显示绑定,但是操作系统却似乎做了些隐蔽的事情。

    首先,在客户端,fd = socket(AF_INET, SOCK_DGRAM, 0),然后就想在此fd下进行recvfrom是收不到对方(假设对方就是服务器吧)的消息是办不到的,
    其实想想也很容易明白,这是fd未和任何端口、IP产生关联要是这样都能收到消息,那真要乱套了。想要在没绑定的情况下受到服务器发来的消息,
    首先客户端得通过fd描述符首先向服务器发信息,然后这时在fd下进行阻塞recvfrom就能收到消息了,如果再在客户端上fd 1= socket(AF_INET, SOCK_DGRAM, 0),
    想在fd1 上进行recvfrom依然收不到消息,因为fd和服务器同过信,但fd1没有,所以fd1收不到,但是从fd1向服务器发消息没问题!所一总结一下就是,
    只有当已通过fd向服务器发送了消息时(并且已经发通了),才能在fd处收到服务器发回来的消息,但是向服务器发送消息就不需要。
    所以说操作系统在此做了些隐蔽的事情,当fd首先向服务器发消息时客户端自动选折IP和一个PORT与该fd关联了起来,(我觉得相当于背后还是绑定了一样)。
    而后面创建的fd1和之前的fd他们出客户端的PORT是不同的(我在服务器端检测了一下),所以通过fd向服务器发了消息但想在新建立的fd1下去recvfrom收不到消息。

     另外,只能对一个socket描述符绑定一次,不能绑定多次,除非前面已经将该描述符close了。

     反过来一个端口也只能被绑定到同一个socket描述符上,除非他们使用的不同的协议。

    注意:如果客户端绑定了,那么在服务器端将无法输出任何东西,在recvfrom()该函数阻塞。

    1.每一次都要进行版本检测。
    2.头文件的包含,#include <WinSock2.h>一定要在#include <Windows.h>的前面。
    如:
    #include <WinSock2.h>
    #include <Windows.h>

  • 相关阅读:
    【STM32 .Net MF开发板学习19】DHT11温湿度传感器通信(上)
    【STM32 .Net MF开发板学习18】GPRS遥控智能小车
    【STM32 .Net MF开发板学习21】蓝牙遥控智能小车(PC模式)
    【STM32 .Net MF开发板学习17】Wifi遥控智能小车
    【STM32 .Net MF开发板学习15】红外遥控智能小车
    【STM32 .Net MF开发板学习20】蓝牙遥控智能小车(手机模式)
    研华物联网论坛和ARM技术研讨会随笔
    STM32F103ZE和STM32F207ZG的芯片区别
    Microsoft .NET Gadgeteer 简介及其它
    Windows Phone_学习第三天 简单
  • 原文地址:https://www.cnblogs.com/gd-luojialin/p/7694165.html
Copyright © 2011-2022 走看看