现在的位置: 首页 > 综合 > 正文

UDP Socket通信学习

2013年03月21日 ⁄ 综合 ⁄ 共 6088字 ⁄ 字号 评论关闭

学习内容,参见《Windows网络编程》第7章 Winsock基础

 

与TCP流式协议不同,UDP为数据报协议。

 

服务端接受数据,客户端发送数据。

UDP服务端流程

  • Socket或WSASocket建立套接字,用SOCK_DGRAM标志。
  • bind绑定到IP地址和端口。
  • recvfrom/WSARecvFrom接受数据。

 

UDP客户端流程

UDP客户端有两种方式,一种为无连接,一种为创建虚拟连接。

方式一 无连接

  • Socket或WSASocket建立套接字,用SOCK_DGRAM标志。
  • 设置服务器地址和端口。
  • sento/WSASendTo发送数据。

方式二 建立虚拟连接

  • Socket或WSASocket建立套接字,用SOCK_DGRAM标志。
  • 设置服务器地址和端口。
  • connect连接服务端。
  • 调用send发送数据。

 

使用windows的Winsock 2编程,需要进行工程配置。

  • 工程右键Properties->ConfigurationProperties->Linker->Input->Additional Dependencies中添加ws2_32.lib。
  • Demo代码采用Multi-Byte方式,设置Properties->ConfigurationProperties->General->Character Set为Use Multi-Byte Character Set。

备注:所有关系到收发数据的缓冲都属于简单的char类型,这些函数没有Unicode版本。当字符集为Unicode时,需要进行字符串转换。

 

服务端源码,UDPServer.cpp。

// UDPServer.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <WinSock2.h>
#include <stdio.h>
#include <stdlib.h>

#define DEFAULT_PORT 5150
#define DEFAULT_COUNT 5
#define DEFAULT_BUFFER_LENGTH 4096

int iPort = DEFAULT_PORT;
DWORD dwCount = DEFAULT_COUNT;
DWORD dwLength = DEFAULT_BUFFER_LENGTH;
BOOL bInterface = FALSE;

char szIterface[32];

//Print usage information and exit
void usage()
{
    printf("usage:sender[-p:int][-i:IP][-n:x][-b:x]\n\n");
    printf("      -p:int  Local port\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 to send \n\n");

    ExitProcess(1);
}

//ValidateArgs
void ValidateArgs(int argc, _TCHAR** argv)
{
    for (int i = 1; i < argc; i++)
    {
        if ((argv[i][0] == _T('-') || (argv[i][0] == _T('/'))))
        {
            switch (tolower(argv[i][1]))
            {
            case _T('p'):
                if (_tcslen(argv[i]) > 3)
                {
                    iPort = _ttoi(&argv[i][3]);
                }
                break;
            case _T('n'):
                //Number of times to receive message
                if (_tcslen(argv[i]) > 3)
                {
                    dwCount = _ttol(&argv[i][3]);
                }
                break;
            case _T('b'):
                //Buffer size
                if (_tcslen(argv[i]) > 3)
                {
                    dwLength = _ttol(&argv[i][3]);
                }
                break;
            case _T('i'):
                //Interface to receive datagrams on
                if (_tcslen(argv[i]) > 3)
                {
                    bInterface = TRUE;
                    _tcscpy_s(szIterface, &argv[i][3]);
                }
                break;
            default:
                usage();
                break;
            }
        }
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    //Parse arguments and load winsock
    ValidateArgs(argc, argv);

    WSADATA wsd;
    if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
    {
        printf("WSAStartup failed!\n");
        return 1;
    }

    //Create the socket, and bind it to a local interface and port
    SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
    if (s == INVALID_SOCKET)
    {
        printf("socket() failed:%d\n", WSAGetLastError());
        return 1;
    }

    SOCKADDR_IN local;
    local.sin_family = AF_INET;
    local.sin_port = htons((short)iPort);
    if (bInterface)
    {
        local.sin_addr.s_addr = inet_addr(szIterface);
    }
    else
    {
        local.sin_addr.s_addr = htonl(INADDR_ANY);
    }

    if (bind(s, (SOCKADDR*)&local, sizeof(local)) == SOCKET_ERROR)
    {
        printf("bind() failed:%d\n", WSAGetLastError());
        return 1;
    }

    //Allocate the receive buffer
    char* recvbuf = (char*)GlobalAlloc(GMEM_FIXED, dwLength);
    if (!recvbuf)
    {
        printf("GlobalAlloc() failed:%d\n", GetLastError());
        return 1;
    }

    //Read the datagrams
    SOCKADDR_IN sender;
    for (int i = 0; i < (int)dwCount; i++)
    {
        int nSenderSize = sizeof(sender);
        int ret = recvfrom(s, recvbuf, dwLength, 0,
            (SOCKADDR*)&sender, &nSenderSize);
        if (ret == SOCKET_ERROR)
        {
            printf("recvfrom() failed:%d\n", WSAGetLastError());
            break;
        }
        else if (ret == 0)
        {
            break;
        }
        else
        {
            recvbuf[ret] = _T('\0');
            printf("[%s] sent me:'%s'\n",
                inet_ntoa(sender.sin_addr), recvbuf);
        }
    }
    closesocket(s);

    GlobalFree(recvbuf);
    WSACleanup();
    return 0;
}

客户端源码,UDPClient.cpp。

// UDPClient.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#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 32

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

//Print usage information and exit
void usage()
{
    printf("usage:sender[-p:int][-r:IP][-c][-n:x][-b:x][-d:c]\n\n");
    printf("      -p:int    Remote port\n");
    printf("      -r:IP     Recipient's IP address or host name\n");
    printf("      -c         Connect to remote IP first\n");
    printf("      -n:x     Number of times to send message\n");
    printf("      -b:x     Size of buffer to send\n");
    printf("      -d:c     Character to fill buffer with\n\n");
    ExitProcess(1);
}

//Parse the command line arguments, and set some global flags to
//indicate what actions to perform
void ValidateArgs(int argc, _TCHAR** argv)
{
    for (int i = 1; i < argc; i++)
    {
        if ((argv[i][0] == _T('-') || (argv[i][0] == _T('/'))))
        {
            switch (tolower(argv[i][1]))
            {
            case _T('p'):
                //Remote port
                if (_tcslen(argv[i]) > 3)
                {
                    iPort = _ttoi(&argv[i][3]);
                }
                break;
            case _T('r'):
                //Recipient's IP addr
                if (_tcslen(argv[i]) > 3)
                {
                    _tcscpy_s(szRecipient, &argv[i][3]);
                }
                break;
            case _T('c'):
                //Connect to recipient's IP addr
                bConnect = TRUE;
                break;
            case _T('n'):
                if (_tcslen(argv[i]) > 3)
                {
                    dwCount = _ttol(&argv[i][3]);
                }
                break;
            case _T('b'):
                if (_tcslen(argv[i]) > 3)
                {
                    dwLength = _ttol(&argv[i][3]);
                }
                break;
            case _T('d'):
                cChar = argv[i][3];
                break;
            default:
                usage();
                break;
            }
        }
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    ValidateArgs(argc, argv);

    WSADATA wsd;
    if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
    {
        printf("WSAStartup failed!\n");
        return 1;
    }

    //Crate the socket
    SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
    if (s == INVALID_SOCKET)
    {
        printf("socket() failed:%d\n", WSAGetLastError());
        return 1;
    }

    //Resolve the recipient's IP address or host name
    SOCKADDR_IN recipient;
    recipient.sin_family = AF_INET;
    recipient.sin_port = htons((short)iPort);

    int nServerLen = (int)_tcslen(szRecipient);
    if (0 == nServerLen)
    {
        struct hostent* host = gethostbyname(szRecipient);
        if (host == NULL)
        {
            printf("gethostbyname() failed:%d\n", WSAGetLastError());
            WSACleanup();
            return 1;
        }

        CopyMemory(&recipient.sin_addr, host->h_addr_list[0], host->h_length);
    }
    else
    {
        recipient.sin_addr.s_addr = inet_addr(szRecipient);
    }

    //Allocate the send buffer
    char* sendbuf = (char*)GlobalAlloc(GMEM_FIXED, dwLength);
    if (!sendbuf)
    {
        printf("GlobalAlloc() failed:%d\n", GetLastError());
        return 1;
    }
    memset(sendbuf, cChar, dwLength);

    if (bConnect)
    {
        //If the connect option is set, "connect" to the recipient
        //and send the data with the send() fuction

        if (connect(s, (SOCKADDR*)&recipient,
            sizeof(recipient)) == SOCKET_ERROR)
        {
            printf("connect() failed:%d\n", WSAGetLastError());
            GlobalFree(sendbuf);
            WSACleanup();
            return 1;
        }

        for (int i = 0; i < (int)dwCount; i++)
        {
            int ret = send(s, sendbuf, dwLength, 0);
            if (ret == SOCKET_ERROR)
            {
                printf("send() failed:%d\n", WSAGetLastError());
                break;
            }
            else if (ret == 0)
            {
                break;
            }
        }
    }
    else
    {
        //Otherwise, use the sendto() function
        for (int i = 0; i < (int)dwCount; i++)
        {
            int ret = sendto(s, sendbuf, dwLength, 0,
                (SOCKADDR*)&recipient, sizeof(recipient));
            if (ret == SOCKET_ERROR)
            {
                printf("send() failed:%d\n", WSAGetLastError());
                break;
            }
            else if (ret == 0)
            {
                break;
            }
        }
    }

    closesocket(s);
    GlobalFree(sendbuf);
    WSACleanup();
    return 0;
}

抱歉!评论已关闭.