⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qostcp.c

📁 《Windows网络编程技术》附书源码源码. 运行环境:9x/Me/NT/2000/XP/ 源码语言:简体中文 第十二章
💻 C
📖 第 1 页 / 共 2 页
字号:
// Module: Qostcp.c
//
// Description:
//    This sample illustrates unicast TCP connections. This sample
//    may act as either a client or server. For both, QOS may be 
//    set before connection or acceptance, during connection or
//    acceptance, after connection or acceptance, or once an 
//    FD_QOS event has been received. The server may handle up to
//    MAX_CONN number of client connections.
//
// Compile:
//    cl -o qostcp.exe qostcp.c printqos.c provider.c ws2_32.lib 
//
// Command Line Parameters/Options
//    qostcp.exe -q:flag -s -c:Server-IP -w
//       -q:[b,d,a,e]        When to request QOS
//           b               Set QOS before bind or connect
//           d               Set QOS during accept cond func
//           a               Set QOS after session setup
//           e               Set QOS only upon receipt of FD_QOS
//       -s                  Act as server
//       -c:Server-IP        Act as client
//       -w                  Wait to send until RESV has arrived
//       -r                  Confirm reservation request
//
#include <winsock2.h>
#include <windows.h>
#include <qos.h>
#include <qossp.h>

#include "provider.h"
#include "printqos.h"

#include <stdio.h>
#include <stdlib.h>

#define QOS_BUFFER_SZ       16000 // Default buffer size for 
                                  // SIO_GET_QOS
#define DATA_BUFFER_SZ       2048 // Send/Recv buffer size

#define SET_QOS_NONE          0   // No QOS
#define SET_QOS_BEFORE        1   // Set QOS on listening socket
#define SET_QOS_DURING        2   // Set QOS in conditional accept
#define SET_QOS_AFTER         3   // Set QOS after accept
#define SET_QOS_EVENT         4   // Wait for FD_QOS and then set

#define MAX_CONN              10

int  iSetQos,          // When to set QOS?
     nConns;
BOOL bServer,          // Client or server?
     bWaitToSend,      // Wait to send data until RESV
     bConfirmResv;
char szServerAddr[64]; // Server's address
QOS  clientQos,        // QOS client structure
     serverQos;        // QOS server structure
RSVP_RESERVE_INFO  qosreserve; 

//
// Setup some common FLOWSPECS
//
const FLOWSPEC flowspec_notraffic = {QOS_NOT_SPECIFIED,
                                     QOS_NOT_SPECIFIED,
                                     QOS_NOT_SPECIFIED,
                                     QOS_NOT_SPECIFIED,
                                     QOS_NOT_SPECIFIED,
                                     SERVICETYPE_NOTRAFFIC,
                                     QOS_NOT_SPECIFIED,
                                     QOS_NOT_SPECIFIED};

const FLOWSPEC flowspec_g711 = {8500,
                                680,
                                17000,
                                QOS_NOT_SPECIFIED,
                                QOS_NOT_SPECIFIED,
                                SERVICETYPE_CONTROLLEDLOAD,
                                340,
                                340};

const FLOWSPEC flowspec_guaranteed = {17000,
                                      1260,
                                      34000,
                                      QOS_NOT_SPECIFIED,
                                      QOS_NOT_SPECIFIED,
                                      SERVICETYPE_GUARANTEED,
                                      340,
                                      340};

//
// Function: SetReserveInfo
//
// Description:
//    For receivers, if a confirmation is requested this must be
//    done with an RSVP_RESERVE_INFO structure
//
void SetQosReserveInfo(QOS *lpqos)
{
    qosreserve.ObjectHdr.ObjectType = RSVP_OBJECT_RESERVE_INFO;
    qosreserve.ObjectHdr.ObjectLength = sizeof(RSVP_RESERVE_INFO);
    qosreserve.Style = RSVP_DEFAULT_STYLE;
    qosreserve.ConfirmRequest = bConfirmResv;
    qosreserve.NumPolicyElement  = 0;
    qosreserve.PolicyElementList = NULL;
    qosreserve.FlowDescList = NULL;

    lpqos->ProviderSpecific.buf = (char *)&qosreserve;
    lpqos->ProviderSpecific.len = sizeof(qosreserve);

    return;
}

//
// Function: InitQos
//
// Description:
//    Setup the client and server QOS structures. This is 
//    broken out into a separate function so you can change 
//    the requested QOS parameters to see how that affects 
//    the application.
//
void InitQos()
{
    clientQos.SendingFlowspec = flowspec_g711;
    clientQos.ReceivingFlowspec =  flowspec_notraffic;
    clientQos.ProviderSpecific.buf = NULL;
    clientQos.ProviderSpecific.len = 0;

    serverQos.SendingFlowspec = flowspec_notraffic;
    serverQos.ReceivingFlowspec = flowspec_g711;
    serverQos.ProviderSpecific.buf = NULL;
    serverQos.ProviderSpecific.len = 0;
    if (bConfirmResv)
        SetQosReserveInfo(&serverQos);
}

//
// Function: usage
//
// Description:
//    Print out usage information.
//
void usage(char *progname)
{
    printf("usage: %s -q:x -s -c:IP\n", progname);
    printf("      -q:[b,d,a,e] When to request QOS\n");
    printf("          b        Set QOS before bind or connect\n");
    printf("          d        Set QOS during accept cond func\n");
    printf("          a        Set QOS after session setup\n");
    printf("          e        Set QOS only upon receipt of FD_QOS\n");
    printf("      -s           Act as server\n");
    printf("      -c:Server-IP Act as client\n");
    printf("      -w           Wait to send until RESV has arrived\n");
    printf("      -r           Confirm reservatin request\n");
    ExitProcess(-1);
}

// 
// Function: ValidateArgs
//
// Description:
//    Parse command line arguments and set global variables to
//    indicate how the application should act
//
void ValidateArgs(int argc, char **argv)
{
    int      i;

    // Initialize globals to a default value
    //
    iSetQos = SET_QOS_NONE;
    bServer = TRUE;
    bWaitToSend = FALSE;
    bConfirmResv = FALSE;

    for(i = 1; i < argc; i++)
    {
        if ((argv[i][0] == '-') || (argv[i][0] == '/'))
        {
            switch (tolower(argv[i][1]))
            {
                case 'q':        // When to set QOS
                    if (tolower(argv[i][3]) == 'b')
                        iSetQos = SET_QOS_BEFORE;
                    else if (tolower(argv[i][3]) == 'd')
                        iSetQos = SET_QOS_DURING;
                    else if (tolower(argv[i][3]) == 'a')
                        iSetQos = SET_QOS_AFTER;
                    else if (tolower(argv[i][3]) == 'e')
                        iSetQos = SET_QOS_EVENT;
                    else
                        usage(argv[0]);
                    break;
                case 's':        // Server
                    printf("Server flag set!\n");
                    bServer = TRUE;
                    break;
                case 'c':        // Client
                    printf("Client flag set!\n");
                    bServer = FALSE;
                    if (strlen(argv[i]) > 3)
                        strcpy(szServerAddr, &argv[i][3]);
                    else
                        usage(argv[0]);
                    break;
                case 'w':       // Wait to send data until
                                // RESV has arrived
                    bWaitToSend = TRUE;
                    break;
                case 'r':
                    bConfirmResv = TRUE;
                    break;
                default:
                    usage(argv[0]);
                    break;
            }
        }
    }
    return;
}

//
// Function: AbleToSend
//
// Description:
//    Checks to send whether data can be sent on the socket before
//    any RESV message have arrived. This checks to see if the 
//    best effort level currently available on the network is 
//    sufficient for the QOS levels that were set on the socket.
//
BOOL AbleToSend(SOCKET s)
{
    int     ret;
    DWORD   dwCode = ALLOWED_TO_SEND_DATA,
            dwValue,
            dwBytes;

    ret = WSAIoctl(s, SIO_CHK_QOS, &dwCode, sizeof(dwCode),
                &dwValue, sizeof(dwValue), &dwBytes, NULL, NULL);
    if (ret == SOCKET_ERROR)
    {
        printf("WSAIoctl() failed: %d\n", WSAGetLastError());
        return FALSE;
    }
    return (BOOL)dwValue;
}

//
// Function: ChkForQosStatus
//
// Description:
//    Check for the presence of a RSVP_STATUS_INFO object and
//    determine if the supplied flags are present in that
//    object
//
DWORD ChkForQosStatus(QOS *lpqos, DWORD dwFlags)
{
    QOS_OBJECT_HDR   *objhdr = NULL;
    RSVP_STATUS_INFO *status = NULL;
    char             *bufptr = NULL;
    BOOL              bDone = FALSE;
    DWORD             objcount = 0;

    if (lpqos->ProviderSpecific.len == 0)
        return 0;

    bufptr = lpqos->ProviderSpecific.buf;
    objhdr = (QOS_OBJECT_HDR *)bufptr;


    while (!bDone)
    {
        if (objhdr->ObjectType == RSVP_OBJECT_STATUS_INFO)
        {
            status = (RSVP_STATUS_INFO *)objhdr;
            if (status->StatusCode & dwFlags)
                return 1;
        }
        else if (objhdr->ObjectType == QOS_OBJECT_END_OF_LIST)
            bDone = TRUE;

        bufptr += objhdr->ObjectLength;
        objcount += objhdr->ObjectLength;
        objhdr = (QOS_OBJECT_HDR *)bufptr;

        if (objcount >= lpqos->ProviderSpecific.len)
            bDone = TRUE;
    }
    return 0;
}

//
// Function: HandleClientEvents
//
// Description:
//    This function is called by the Server function to handle
//    events which occured on client SOCKET handles. The socket
//    array is passed in along with the event array and the index
//    of the client who received the signal. Within the function
//    the event is decoded and the appropriate action occurs.
//
void HandleClientEvents(SOCKET socks[], HANDLE events[], int index)
{
    WSANETWORKEVENTS  ne;
    char              databuf[4096];
    WSABUF            wbuf;
    DWORD             dwBytesRecv,
                      dwFlags;
    int               ret,
                      i;

    // Enumerate the network events that occured
    //
    ret = WSAEnumNetworkEvents(socks[index], events[index], &ne);
    if (ret == SOCKET_ERROR)
    {
        printf("WSAEnumNetworkEvents() failed: %d\n", 
            WSAGetLastError());
        return;
    }
    // Data to be read
    //
    if ((ne.lNetworkEvents & FD_READ) == FD_READ)
    {
        wbuf.buf = databuf;
        wbuf.len = 4096;

        if (ne.iErrorCode[FD_READ_BIT])
            printf("FD_READ error: %d\n", 
                ne.iErrorCode[FD_READ_BIT]);
        else
            printf("FD_READ\n");

        dwFlags = 0;
        ret = WSARecv(socks[index], &wbuf, 1, &dwBytesRecv, 
            &dwFlags, NULL, NULL);
        if (ret == SOCKET_ERROR)
        {
            printf("WSARecv() failed: %d\n", WSAGetLastError());
            return;
        }
        wbuf.len = dwBytesRecv;

        printf("Read: %d bytes\n", dwBytesRecv);
    }
    // Able to write data, nothing to do here
    //
    if ((ne.lNetworkEvents & FD_WRITE) == FD_WRITE)
    {
        if (ne.iErrorCode[FD_WRITE_BIT])
            printf("FD_WRITE error: %d\n", 
                ne.iErrorCode[FD_WRITE_BIT]);
        else
            printf("FD_WRITE\n");
    }
    // The client closed the connection. Close the socket on our 
    // end and clean up the data structures.
    //
    if ((ne.lNetworkEvents & FD_CLOSE) == FD_CLOSE)
    {
        if (ne.iErrorCode[FD_CLOSE_BIT])
            printf("FD_CLOSE error: %d\n", 
                ne.iErrorCode[FD_CLOSE_BIT]);
        else
            printf("FD_CLOSE ...\n");
        closesocket(socks[index]);
        WSACloseEvent(events[index]);

        socks[index] = INVALID_SOCKET;
        //
        // Remote the client socket entry from the array and 
        // compact the remaining clients to the beginning of the 
        // array
        //
        for(i = index; i < MAX_CONN - 1; i++)
            socks[i] = socks[i + 1];
        nConns--;
    }
    // Received an FD_QOS event. This could mean several things.
    //
    if ((ne.lNetworkEvents & FD_QOS) == FD_QOS)
    {
        char        buf[QOS_BUFFER_SZ];
        QOS        *lpqos = NULL;
        DWORD       dwBytes;

        if (ne.iErrorCode[FD_QOS_BIT])
            printf("FD_QOS error: %d\n", 
                ne.iErrorCode[FD_QOS_BIT]);
        else
            printf("FD_QOS\n");

        lpqos = (QOS *)buf;
        lpqos->ProviderSpecific.buf = &buf[sizeof(QOS)];
        lpqos->ProviderSpecific.len = sizeof(buf) - sizeof(QOS);

        ret = WSAIoctl(socks[index], SIO_GET_QOS, NULL, 0,
                buf, QOS_BUFFER_SZ, &dwBytes, NULL, NULL);
        if (ret == SOCKET_ERROR)
        {
            printf("WSAIoctl(SIO_GET_QOS) failed: %d\n", 
                WSAGetLastError());
            return;
        }
        PrintQos(lpqos);
        //
        // See if we're set for receiving FD_QOS events only. 
        // If so we need to actually invoke QOS on the connection 
        // now otherwise client will never receive a RESV message.
        //
        if (iSetQos == SET_QOS_EVENT)
        {
            lpqos->ReceivingFlowspec.ServiceType = 
                serverQos.ReceivingFlowspec.ServiceType;

            ret = WSAIoctl(socks[index], SIO_SET_QOS, lpqos, 
                dwBytes, NULL, 0, &dwBytes, NULL, NULL);
            if (ret == SOCKET_ERROR)
            {
                printf("WSAIoctl(SIO_SET_QOS) failed: %d\n", 
                    WSAGetLastError());
                return;
            }
            //
            // Change iSetQos so we don't set QOS again if we 
            // receive another FD_QOS event
            //
            iSetQos = SET_QOS_BEFORE;
        }
    }
    return;
}

//
// Function: SrvCondAccept
//
// Description:
//    This is the conditional function for WSAAccept. There is a 
//    limitation with the QOS service provider that the QOS values
//    passed into here are unreliable so the option SET_QOS_DURING 
//    is rather useless unless we call SIO_SET_QOS with are own 
//    values (as opposed to what the client is requesting since 
//    that is what is supposed to be returned in lpSQOS). Note that 
//    on Windows 98 if lpSQOS is not NULL you have to use set some
//    kind of QOS values (with SIO_SET_QOS) in the conditional 
//    function otherwise WSAAccept will fail.
//
int CALLBACK SrvCondAccept(LPWSABUF lpCallerId, 
    LPWSABUF lpCallerdata, LPQOS lpSQOS, LPQOS lpGQOS, 
    LPWSABUF lpCalleeId, LPWSABUF lpCalleeData, GROUP *g, 
    DWORD dwCallbackData)
{
    DWORD       dwBytes = 0;
    SOCKET      s = (SOCKET)dwCallbackData;
    SOCKADDR_IN client;
    int         ret;

    if (nConns == MAX_CONN)
        return CF_REJECT;

    memcpy(&client, lpCallerId->buf, lpCallerId->len);
    printf("Client request: %s\n", inet_ntoa(client.sin_addr));

    if (iSetQos == SET_QOS_EVENT)
    {
        printf("Setting for event!\n");
        serverQos.SendingFlowspec.ServiceType |= 
            SERVICE_NO_QOS_SIGNALING;
        serverQos.ReceivingFlowspec.ServiceType |= 
            SERVICE_NO_QOS_SIGNALING;

        ret = WSAIoctl(s, SIO_SET_QOS, &serverQos, 
            sizeof(serverQos), NULL, 0, &dwBytes, NULL, NULL);
        if (ret == SOCKET_ERROR)
        {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -