UDP client/server 通过不同 IP 和端口上的 2 个套接字进行通信的程序

UDP client/server program that communicates over 2 sockets on different IPs and ports

我有一台服务器和一台客户端。服务器和客户端有 2 个 NIC。这是在 Fedora 26 上开发的。

我通过 "data channel" 10.0.0.210:21323 -> 10.0.0.209 从客户端发送包含数据包编号 (qualitySequenceCounter) 和 40 字节编码音频文件 (.chn) 的缓冲区: 21323。当服务器收到数据时,它会解包 qualitySequenceCounter 和音频数据。然后服务器应该通过 "control channel" 10.0.0.121:8080 -> 10.0.0.122:8080 将 qualitySequenceCounter 发送回客户端。服务器通过 "control channel" 发送数据,但客户端从未收到它,只是挂在那里等待。我不知道我错过了什么或做错了什么。

服务器

// server2s.cpp
// parsing files
#include <iostream>
#include <fstream>
#include <string>
#include <sys/stat.h>

//network stuff
#include <sys/socket.h>
#include <netdb.h>
#include <memory.h>
#include <stdio.h>
#include <stdarg.h>
//#define SOL_IP IPPROTO_IP
#ifndef INVALID_SOCKET
#define INVALID_SOCKET -1
#endif
#define sockerrno errno


char szLineBuf[500];

int iNetSock = INVALID_SOCKET;
int iRequest = 1;
struct sockaddr_in sAddr, cAddr;
socklen_t iAddrLen = sizeof(sAddr);
socklen_t cAddrLen = sizeof(cAddr);

int perr(const char *pszFormat, ...)
{
    va_list argList;
    va_start(argList, pszFormat);
    vsnprintf(szLineBuf, sizeof(szLineBuf)-10, pszFormat, argList);
    szLineBuf[sizeof(szLineBuf)-10] = '[=11=]';
    printf("Error: %s\n", szLineBuf);
    return 0;
}


//++++++++++++++++++++++++++++++++++++++
// second socket for control channel
char szLineBufCC[500];

int iNetSockCC = INVALID_SOCKET;
int iRequestCC = 1;
struct sockaddr_in sAddrCC, cAddrCC;
socklen_t iAddrLenCC = sizeof(sAddrCC);
socklen_t cAddrLenCC = sizeof(cAddrCC);

int perrCC(const char *pszFormat, ...)
{
    va_list argList;
    va_start(argList, pszFormat);
    vsnprintf(szLineBufCC, sizeof(szLineBufCC)-10, pszFormat, argList);
    szLineBufCC[sizeof(szLineBufCC)-10] = '[=11=]';
    printf("Error CC: %s\n", szLineBufCC);
    return 0;
}

// end
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


int main(int argc, const char * argv[]) {
    //file I/O stuff
    // this is the char array that we will populate with the control channel counter and audio data
    char buffer[44];
    // buffer used only for audio data to be written to file
    char audioBuffer[40];

    // this is the char array for the control channel counter
    char bufferCC[4];

    // this is for opening the audio file
    std::ifstream inFile;
    std::ofstream outFile;
    // initializing the location of the audio channel read
    long fileLoc = 0;
    // initializing the control channel counter
    int qualitySequenceCounter=0;
    // initializing how we will be able to tell where we are in the audio file; need to add code to loop back to beginning of the audio file once we reach the end
    struct stat results;

    //network stuff
    const char *pszHost = "10.0.0.209";
    unsigned short iPort = 21323;


    //+++++++++++++++++++++++++++++++++++++++
    // second socket for control channel
    //network stuff
    const char *pszHostCC = "10.0.0.121";
    unsigned short iPortCC = 8080;
    // end
    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^    


    //open up audio file for parsing
    outFile.open("/home/mode1_received.chn", std::ios::out | std::ios::binary);

    //if the file doesn't open, tell me
    if(!outFile.is_open()){
       std::cout << "Error opening audio file\n";
    }

    if (stat("/home/mode1_received.chn", &results) == 0) {
        // The size of the file in bytes is in
        // results.st_size
        std::cout << "File size:" << results.st_size << "\n";
    } 
    else {
        std::cout << "An error occured getting the file length";
        // An error occurred
    }

    //establish the IP component
    memset((char *)&sAddr, 0,sizeof(sAddr));
    memset((char *)&cAddr, 0,sizeof(cAddr));
    sAddr.sin_family      = AF_INET;
    sAddr.sin_port        = htons(iPort);

    struct hostent *pHost = gethostbyname(pszHost);
    memcpy(&sAddr.sin_addr.s_addr, pHost->h_addr, pHost->h_length);

    //creates the UDP socket to send data to
    if ((iNetSock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        return 9+perr("cannot create socket");


    // Bind the socket with the server address 
    if ( bind(iNetSock, (const struct sockaddr *)&sAddr,  
            sizeof(sAddr)) < 0 ) 
    { 
        perror("bind failed"); 
        exit(EXIT_FAILURE); 
    } 


    //++++++++++++++++++++++++++++++++++++++
    // second socket for CC
    //establish the IP component
    memset((char *)&sAddrCC, 0,sizeof(sAddrCC));
    memset((char *)&cAddrCC, 0,sizeof(cAddrCC));
    sAddrCC.sin_family      = AF_INET;
    sAddrCC.sin_port        = htons(iPortCC);

    struct hostent *pHostCC = gethostbyname(pszHostCC);
    memcpy(&sAddrCC.sin_addr.s_addr, pHostCC->h_addr, pHostCC->h_length);

    //creates the UDP socket to send data to
    if ((iNetSockCC = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        return 9+perrCC("cannot create socket for CC: Control Channel");


    // Bind the socket with the server address 
    if ( bind(iNetSockCC, (const struct sockaddr *)&sAddrCC,  
            sizeof(sAddrCC)) < 0 ) 
    { 
        perror("bind failed for CC"); 
        exit(EXIT_FAILURE); 
    } 
    // End
    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


    // divide size of audio file by 40

    while(qualitySequenceCounter < 103574){

        // Get data
        unsigned int n; 
        socklen_t len = sizeof(cAddr);
        //char *pData = &buffer[0];
        n = recvfrom(iNetSock, (char *)buffer, 44,  
                MSG_WAITALL, ( struct sockaddr *) &cAddr, 
                &len); 
        printf("data received\n");        
        memcpy(&qualitySequenceCounter, buffer, sizeof(int));
        memcpy(&audioBuffer, &buffer[4], 40);

        printf("qualitySequenceCounter : %u\n", qualitySequenceCounter);        

        // this copies our counter that we are using for the feedback loop into the 4 byte char array
        memcpy(&bufferCC[0], (char *)&(qualitySequenceCounter), sizeof(int));
        // this sets up the payload for the UDP transmission
        //char *pDataCC = &bufferCC[0];
        // sending the data via UDP
        sendto(iNetSockCC, bufferCC, 4, 0, (struct sockaddr *)&cAddrCC, cAddrLenCC);
        printf("data sent back\n");

        // this code allows us to check the counter by printing it to std out
        /*int counterCheck = *((int *)buffer);

        std::cout << "Counter check: " << counterCheck << "\n";

        const char* beg = buffer;
        const char* end = beg + sizeof(buffer);
        while(beg != end)
            std::cout << std::bitset<8>(*beg++) << ' ';
        std::cout << '\n';
        */
        //printf("qualitySequenceCounter : %u\n", qualitySequenceCounter);

        //if (buffer == NULL)
        //  break;
        outFile << audioBuffer;
        //buffer[n] = '[=11=]'; 
        //printf("Client : %s\n", pData); 
        //printf("Client : %u\n", n);

        // qualcounter is 103574

        // will need to reset the fileLoc counter to 0 once we reach the end of the audio file to loop the demo
    }

    //close output file
    outFile.close();

    return 0;
}

客户端

// client2s.cpp
// parsing files
#include <iostream>
#include <fstream>
#include <string>
#include <sys/stat.h>

//network stuff
#include <sys/socket.h>
#include <netdb.h>
#include <memory.h>
#include <stdio.h>
#include <stdarg.h>
//#define SOL_IP IPPROTO_IP
#ifndef INVALID_SOCKET
#define INVALID_SOCKET -1
#endif
#define sockerrno errno

char szLineBuf[500];

int iNetSock = INVALID_SOCKET;
int iRequest = 1;
struct sockaddr_in sAddr;
socklen_t iAddrLen = sizeof(sAddr);

int perr(const char *pszFormat, ...)
{
    va_list argList;
    va_start(argList, pszFormat);
    vsnprintf(szLineBuf, sizeof(szLineBuf)-10, pszFormat, argList);
    szLineBuf[sizeof(szLineBuf)-10] = '[=12=]';
    printf("Error: %s\n", szLineBuf);
    return 0;
}


//++++++++++++++++++++++++++++++++++++++++
// second socket for control channel
char szLineBufCC[500];

int iNetSockCC = INVALID_SOCKET;
int iRequestCC = 1;
struct sockaddr_in sAddrCC;
socklen_t iAddrLenCC = sizeof(sAddrCC);

int perrCC(const char *pszFormat, ...)
{
    va_list argList;
    va_start(argList, pszFormat);
    vsnprintf(szLineBufCC, sizeof(szLineBufCC)-10, pszFormat, argList);
    szLineBufCC[sizeof(szLineBufCC)-10] = '[=12=]';
    printf("Error with CC: %s\n", szLineBufCC);
    return 0;
}
// End
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


int main(int argc, const char * argv[]) {
    //file I/O stuff
    // this is the char array that we will populate with the control channel counter and audio data
    char buffer[44];
    // this is the char array for the control channel counter
    char bufferCC[4];

    // this is for opening the audio file
    std::ifstream inFile;
    // initializing the location of the audio channel read
    long fileLoc = 0;
    // initializing the control channel counter
    int qualitySequenceCounter=0;
    // counter received over control channel CC
    int qualityCC=0;
    // initializing how we will be able to tell where we are in the audio file; need to add code to loop back to beginning of the audio file once we reach the end
    struct stat results;

    //network stuff
    const char *pszHost = "10.0.0.209";
    unsigned short iPort = 21323;


    //++++++++++++++++++++++++++++++++++++++++
    // second socket for control channel
    //network stuff
    const char *pszHostCC = "10.0.0.121";
    unsigned short iPortCC = 8080;
    // End
    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


    //open up audio file for parsing
    inFile.open("/home/mode1.chn", std::ios::in | std::ios::binary);

    //if the file doesn't open, tell me
    if(!inFile.is_open()){
        std::cout << "Error opening audio file\n";
    }

    if (stat("/home/mode1.chn", &results) == 0)
        // The size of the file in bytes is in
        // results.st_size
        std::cout << "File size:" << results.st_size << "\n";
        else
            std::cout << "An error occured getting the file length";
            // An error occurred}

    //establish the IP component
    memset((char *)&sAddr, 0,sizeof(sAddr));
    sAddr.sin_family      = AF_INET;
    sAddr.sin_port        = htons(iPort);

    struct hostent *pHost = gethostbyname(pszHost);
    memcpy(&sAddr.sin_addr.s_addr, pHost->h_addr, pHost->h_length);

    //creates the UDP socket to send data to
    if ((iNetSock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        return 9+perr("cannot create socket");


    //++++++++++++++++++++++++++++++++++++
    // second socket for control channel
    //establish the IP component
    memset((char *)&sAddrCC, 0,sizeof(sAddrCC));
    sAddrCC.sin_family      = AF_INET;
    sAddrCC.sin_port        = htons(iPortCC);

    struct hostent *pHostCC = gethostbyname(pszHostCC);
    memcpy(&sAddrCC.sin_addr.s_addr, pHostCC->h_addr, pHostCC->h_length);

    //creates the UDP socket to send data to
    if ((iNetSockCC = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        return 9+perrCC("cannot create socket for Control Channel");
    // End
    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


    while(qualitySequenceCounter < results.st_size && fileLoc >= 0){
        // will need to open file inside the while loop once we add the control channel feedback, else we need to open all of the different files at once (which might be easier) and switch back and forth between multiple open files
        // this reads in 40 bytes of data and places it 4 bytes into the char array
        inFile.read(&buffer[4],40);
        // getting the location of where we are in the audio file in case we need to switch audio files
        fileLoc = inFile.tellg();
        // this copies our counter that we are using for the feedback loop into the first 4 bytes of the char array
        memcpy(&buffer[0], (char *)&(qualitySequenceCounter), sizeof(int));
        // this sets up the payload for the UDP transmission
        char *pData = &buffer[0];

        // sending the data via UDP
        sendto(iNetSock, pData, 44, 0, (struct sockaddr *)&sAddr, iAddrLen);
        printf("data sent\n");

        //++++++++++++++++++++++++++++++++++++
        // second socket for control channel
        // Get data
        unsigned int nCC; 
        socklen_t lenCC = sizeof(sAddrCC);
        //char *pData = &buffer[0];
        nCC = recvfrom(iNetSockCC, (char *)bufferCC, 4,  
                MSG_WAITALL, ( struct sockaddr *) &sAddrCC, 
                &lenCC); 
        printf("data received again\n");   
        memcpy(&qualityCC, bufferCC, sizeof(int));
        printf("qualityCC : %u\n", qualityCC);
        // End
        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


        // increment the feedback counter for the control channel
        qualitySequenceCounter++;
        // this code allows us to check the counter by printing it to std out
 /*       int counterCheck = *((int *)buffer);

        std::cout << "Counter check: " << counterCheck << "\n";


        const char* beg = buffer;
        const char* end = beg + sizeof(buffer);
        while(beg != end)
            std::cout << std::bitset<8>(*beg++) << ' ';
        std::cout << '\n';
  */
        // will need to reset the fileLoc counter to 0 once we reach the end of the audio file to loop the demo
    }

    //close input file
    inFile.close();

    return 0;
}

客户端从不将 iNetSockCC 绑定到任何特定端口,因此它不会侦听任何特定端口。那么它如何才能收到服务器的响应呢?我有点不明白你为什么要两对插座。为什么不让服务器通过发回源来回复客户端?

这些是解决我使用 David Schwartz 的建议发布的问题的代码的当前工作版本(请参阅对上述问题的评论)。

这是在使用两个虚拟机 运行 Fedora 26 的 MacBook Pro 上开发的。然后在单独的笔记本电脑 运行 Fedora 26 的专用网络上进一步测试。Wireshark 和 netem 已经不可或缺

服务器(s2.cpp)

// Server
// s2.cpp
// Created by JParks on 7/12/19.
// Last edit: Thur, Sept 5, 3:19PM 2019

//parsing files
#include <iostream>
#include <fstream>
#include <string>
#include <sys/stat.h>

//network stuff
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <memory.h>
#include <stdio.h>
#include <stdarg.h>
#include <thread>
#ifndef INVALID_SOCKET
#define INVALID_SOCKET -1
#endif
#define sockerrno errno


char szLineBuf[500];
char szLineBufCC[500];

//char buffer[44];

// Server data interface: enp0s3
const char *server_data_channel_ip = "10.0.0.209";

// Server control interface: enp0s8
const char *server_control_channel_ip = "10.0.0.121";


// Client data interface: enp0s3
const char *client_data_channel_ip = "10.0.0.149";

// Client control interface: enp0s8
const char *client_control_channel_ip = "10.0.0.232";


// Ports for data and control channels
unsigned short dataPort = 21323;
unsigned short controlPort = 8080;

// Data Socket
int iNetSock = INVALID_SOCKET;
int iRequest = 1;
struct sockaddr_in sAddr, cAddr;
socklen_t sAddrLen = sizeof(sAddr);
socklen_t cAddrLen = sizeof(cAddr);

// Control Socket
int iNetSockCC = INVALID_SOCKET;
int iRequestCC = 1;
struct sockaddr_in sAddrCC, cAddrCC;
socklen_t sAddrLenCC = sizeof(sAddrCC);
socklen_t cAddrLenCC = sizeof(cAddrCC);


int perr(const char *pszFormat, ...)
{
    va_list argList;
    va_start(argList, pszFormat);
    vsnprintf(szLineBuf, sizeof(szLineBuf)-10, pszFormat, argList);
    szLineBuf[sizeof(szLineBuf)-10] = '[=10=]';
    printf("Error: %s\n", szLineBuf);
    return 0;
}


int perrCC(const char *pszFormat, ...)
{
    va_list argList;
    va_start(argList, pszFormat);
    vsnprintf(szLineBufCC, sizeof(szLineBufCC)-10, pszFormat, argList);
    szLineBufCC[sizeof(szLineBufCC)-10] = '[=10=]';
    printf("Error CC: %s\n", szLineBufCC);
    return 0;
}


int main(int argc, const char * argv[]) {

    //file I/O stuff
    // this is the char array that we will populate with the control channel counter and audio data

    char buffer[324];

    // buffer used only for audio data to be written to file
    char audioBuffer[320];

    // this is the char array for the control channel counter
    char bufferCC[4];

    // this is for opening the audio file
    std::ifstream inFile;
    std::ofstream outFile;
    // initializing the location of the audio channel read
    long fileLoc = 0;
    // initializing the control channel counter
    int qualitySequenceCounter=0;
    // initializing how we will be able to tell where we are in the audio file; need to add code to loop back to beginning of the audio file once we reach the end
    struct stat results;

    //open up audio file for parsing
    outFile.open("/home/jparks/Downloads/mode1_received.chn", std::ios::out | std::ios::binary);

    //if the file doesn't open, tell me
    if(!outFile.is_open()){
       std::cout << "Error opening audio file\n";
    }

    if (stat("/home/jparks/Downloads/mode1_received.chn", &results) == 0) {
        // The size of the file in bytes is in
        // results.st_size
        std::cout << "File size:" << results.st_size << "\n";
    } 
    else {
        std::cout << "An error occured getting the file length";
        // An error occurred
    }


    //network stuff
    // Data channel
    const char *pszHost = server_data_channel_ip;

    //establish the IP component
    memset((char *)&sAddr, 0,sizeof(sAddr));
    sAddr.sin_family      = AF_INET;
    sAddr.sin_addr.s_addr = inet_addr(server_data_channel_ip);
    sAddr.sin_port        = htons(dataPort);

    struct hostent *pHost = gethostbyname(pszHost);
    memcpy(&sAddr.sin_addr.s_addr, pHost->h_addr, pHost->h_length);

    memset((char *)&cAddr, 0,sizeof(cAddr));
    cAddr.sin_family      = AF_INET;
    cAddr.sin_addr.s_addr = inet_addr(client_data_channel_ip);
    cAddr.sin_port        = htons(dataPort);

    //creates the UDP socket to send data to
    if ((iNetSock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        return 9+perr("cannot create socket");


    // Bind the socket with the server address 
    if ( bind(iNetSock, (const struct sockaddr *)&sAddr,  
            sizeof(sAddr)) < 0 ) 
    { 
        perror("bind failed"); 
        exit(EXIT_FAILURE); 
    }

    //++++++++++++++++++++++++++++++++++++++
    // second socket for CC
    // Control Channel
    const char *pszHostCC = server_control_channel_ip;

    //establish the IP component
    memset((char *)&sAddrCC, 0,sizeof(sAddrCC));
    sAddrCC.sin_family      = AF_INET;
    sAddrCC.sin_addr.s_addr = inet_addr(server_control_channel_ip);
    sAddrCC.sin_port        = htons(controlPort);

    struct hostent *pHostCC = gethostbyname(pszHostCC);
    memcpy(&sAddrCC.sin_addr.s_addr, pHostCC->h_addr, pHostCC->h_length);

    memset((char *)&cAddrCC, 0,sizeof(cAddrCC));
    cAddrCC.sin_family      = AF_INET;
    cAddrCC.sin_addr.s_addr = inet_addr(client_control_channel_ip);
    cAddrCC.sin_port        = htons(controlPort);

    //creates the UDP socket to send data to
    if ((iNetSockCC = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        return 9+perrCC("cannot create socket for CC: Control Channel");


    // Bind the socket with the server address 
    if ( bind(iNetSockCC, (const struct sockaddr *)&sAddrCC,  
            sizeof(sAddrCC)) < 0 ) 
    { 
        perror("bind failed for CC"); 
        exit(EXIT_FAILURE); 
    } 

    //std::thread t1(task1, iNetSock, buffer, cAddr, cAddrLen, qualitySequenceCounter, audioBuffer);

    // divide size of audio file by 320
    // audio data file size: 4142984 -> divide by 320 to get number of packets ~= 12,945
    // Audio needs to be decoded according to Steve's variation of codec G.711 

    while(qualitySequenceCounter < 12945){


        // Get data
        unsigned int n; 
        //socklen_t len = sizeof(cAddr);
        //char *pData = &buffer[0];
        n = recvfrom(iNetSock, (char *)buffer, 324,  
                MSG_WAITALL, ( struct sockaddr *) &cAddr, 
                &cAddrLen); 

        printf("data received\n");        
        memcpy(&qualitySequenceCounter, buffer, sizeof(int));
        memcpy(&audioBuffer, &buffer[4], 320);

        printf("qualitySequenceCounter : %u\n", qualitySequenceCounter);  


        // this copies our counter that we are using for the feedback loop into the 4 byte char array
        memcpy(&bufferCC[0], (char *)&(qualitySequenceCounter), sizeof(int));
        // this sets up the payload for the UDP transmission
        //char *pDataCC = &bufferCC[0];
        // sending the data via UDP
        sendto(iNetSockCC, bufferCC, 4, 0, (struct sockaddr *)&cAddrCC, cAddrLenCC);
        printf("data sent back\n");

        // this code allows us to check the counter by printing it to std out
        /*int counterCheck = *((int *)buffer);

        std::cout << "Counter check: " << counterCheck << "\n";

        const char* beg = buffer;
        const char* end = beg + sizeof(buffer);
        while(beg != end)
            std::cout << std::bitset<8>(*beg++) << ' ';
        std::cout << '\n';
        */
        //printf("qualitySequenceCounter : %u\n", qualitySequenceCounter);

        //if (buffer == NULL)
        //  break;
        outFile << audioBuffer;
        //buffer[n] = '[=10=]'; 
        //printf("Client : %s\n", pData); 
        //printf("Client : %u\n", n);

        // qualcounter is 103574

        // will need to reset the fileLoc counter to 0 once we reach the end of the audio file to loop the demo
    }

    //close output file
    outFile.close();

    return 0;
}

客户端 (c2.cpp)

// Client
// c2.cpp
// AudioParseSendReflect
// Last edit: Thur, Sept 5, 3:19PM 2019

//parsing files
#include <iostream>
#include <fstream>
#include <string>
#include <sys/stat.h>

//network stuff
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <memory.h>
#include <stdio.h>
#include <stdarg.h>
#include <thread>
#include <chrono>
#ifndef INVALID_SOCKET
#define INVALID_SOCKET -1
#endif
#define sockerrno errno

char szLineBuf[500];
char szLineBufCC[500];

// Client data interface: enp0s3
const char *client_data_channel_ip = "10.0.0.149";

// Client control interface: enp0s8
const char *client_control_channel_ip = "10.0.0.232";


// Server data interface: enp0s3
const char *server_data_channel_ip = "10.0.0.209";

// Server control interface: enp0s8
const char *server_control_channel_ip = "10.0.0.121";


// Ports for data and control channels
unsigned short dataPort = 21323;
unsigned short controlPort = 8080;

// Data Socket
int iNetSock = INVALID_SOCKET;
int iRequest = 1;
struct sockaddr_in sAddr, cAddr;
socklen_t sAddrLen = sizeof(sAddr);
socklen_t cAddrLen = sizeof(cAddr);

// Control Socket
int iNetSockCC = INVALID_SOCKET;
int iRequestCC = 1;
struct sockaddr_in sAddrCC, cAddrCC;
socklen_t sAddrLenCC = sizeof(sAddrCC);
socklen_t cAddrLenCC = sizeof(cAddrCC);

int perr(const char *pszFormat, ...)
{
    va_list argList;
    va_start(argList, pszFormat);
    vsnprintf(szLineBuf, sizeof(szLineBuf)-10, pszFormat, argList);
    szLineBuf[sizeof(szLineBuf)-10] = '[=11=]';
    printf("Error: %s\n", szLineBuf);
    return 0;
}



int perrCC(const char *pszFormat, ...)
{
    va_list argList;
    va_start(argList, pszFormat);
    vsnprintf(szLineBufCC, sizeof(szLineBufCC)-10, pszFormat, argList);
    szLineBufCC[sizeof(szLineBufCC)-10] = '[=11=]';
    printf("Error with CC: %s\n", szLineBufCC);
    return 0;
}


int main(int argc, const char * argv[]) {
    //file I/O stuff
    // this is the char array that we will populate with the control channel counter and audio data
    char buffer[324];
    // this is the char array for the control channel counter
    char bufferCC[4];

    // this is for opening the audio file
    std::ifstream inFile;
    // initializing the location of the audio channel read
    long fileLoc = 0;
    // initializing the control channel counter
    int qualitySequenceCounter=0;
    // counter received over control channel CC
    int qualityCC=0;
    // initializing how we will be able to tell where we are in the audio file; need to add code to loop back to beginning of the audio file once we reach the end
    struct stat results;

    //open up audio file for parsing
    inFile.open("/home/jparks/Downloads/mode1.chn", std::ios::in | std::ios::binary);

    //if the file doesn't open, tell me
    if(!inFile.is_open()){
        std::cout << "Error opening audio file\n";
    }

    if (stat("/home/jparks/Downloads/mode1.chn", &results) == 0) {
        // The size of the file in bytes is in
        // results.st_size
        std::cout << "File size:" << results.st_size << "\n";
    } 
    else {
            std::cout << "An error occured getting the file length";
            // An error occurred
    }

    //network stuff
    // Data Channel
    const char *pszHost = client_data_channel_ip;

    //establish the IP component
    memset((char *)&sAddr, 0,sizeof(sAddr));
    sAddr.sin_family      = AF_INET;
    sAddr.sin_addr.s_addr = inet_addr(server_data_channel_ip);
    sAddr.sin_port        = htons(dataPort);

    memset((char *)&cAddr, 0,sizeof(cAddr));
    cAddr.sin_family      = AF_INET;
    cAddr.sin_addr.s_addr = inet_addr(client_data_channel_ip);
    cAddr.sin_port        = htons(dataPort);

    struct hostent *pHost = gethostbyname(pszHost);
    memcpy(&cAddr.sin_addr.s_addr, pHost->h_addr, pHost->h_length);

    //creates the UDP socket to send data to
    if ((iNetSock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        return 9+perr("cannot create socket");

    // Bind the socket with the server address 
    if ( bind(iNetSock, (const struct sockaddr *)&cAddr,  
            sizeof(cAddr)) < 0 ) 
    { 
        perror("bind failed"); 
        exit(EXIT_FAILURE); 
    } 


    //++++++++++++++++++++++++++++++++++++
    // second socket for control channel
    // Control Channel
    const char *pszHostCC = client_control_channel_ip;

    //establish the IP component
    memset((char *)&sAddrCC, 0,sizeof(sAddrCC));
    sAddrCC.sin_family      = AF_INET;
    sAddrCC.sin_addr.s_addr = inet_addr(server_control_channel_ip);
    sAddrCC.sin_port        = htons(controlPort);

    memset((char *)&cAddrCC, 0,sizeof(cAddrCC));
    cAddrCC.sin_family      = AF_INET;
    cAddrCC.sin_addr.s_addr = inet_addr(client_control_channel_ip);
    cAddrCC.sin_port        = htons(controlPort);

    struct hostent *pHostCC = gethostbyname(pszHostCC);
    memcpy(&cAddrCC.sin_addr.s_addr, pHostCC->h_addr, pHostCC->h_length);

    //creates the UDP socket to send data to
    if ((iNetSockCC = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        return 9+perrCC("cannot create socket for Control Channel");

    // Bind the socket with the server address 
    if ( bind(iNetSockCC, (const struct sockaddr *)&cAddrCC,  
            sizeof(cAddrCC)) < 0 ) 
    { 
        perror("bind failed"); 
        exit(EXIT_FAILURE); 
    } 

    // audio data file size: 4142984 -> divide by 320 to get number of packets ~= 12,945
    // audio is encoded using Steve's variation of codec G.711 


    while(qualitySequenceCounter < results.st_size && fileLoc >= 0){
        // will need to open file inside the while loop once we add the control channel feedback, else we need to open all of the different files at once (which might be easier) and switch back and forth between multiple open files
        // this reads in 40 bytes of data and places it 4 bytes into the char array
        inFile.read(&buffer[4],320);
        // getting the location of where we are in the audio file in case we need to switch audio files
        fileLoc = inFile.tellg();
        // this copies our counter that we are using for the feedback loop into the first 4 bytes of the char array
        memcpy(&buffer[0], (char *)&(qualitySequenceCounter), sizeof(int));
        // this sets up the payload for the UDP transmission
        char *pData = &buffer[0];

    //if(qualitySequenceCounter == 1000 || qualitySequenceCounter == 1001 || qualitySequenceCounter == 1002 ||qualitySequenceCounter == 1003) {
        //  printf("packet 1000 is dropped\n");
        //qualitySequenceCounter++;
    //} else {

        // sending the data via UDP
        sendto(iNetSock, pData, 324, 0, (struct sockaddr *)&sAddr, sAddrLen);
        printf("data sent\n");

        std::this_thread::sleep_for(std::chrono::nanoseconds(20000000));
        printf("delay over\n");
        //++++++++++++++++++++++++++++++++++++
        // second socket for control channel
        // Get data
        unsigned int nCC; 
        //socklen_t lenCC = sizeof(sAddrCC);
        //char *pData = &buffer[0];
        nCC = recvfrom(iNetSockCC, (char *)bufferCC, 4,  
                MSG_WAITALL, ( struct sockaddr *) &sAddrCC, 
                &sAddrLenCC); 
        printf("data received again\n");   
        memcpy(&qualityCC, bufferCC, sizeof(int));
        printf("qualityCC : %u\n", qualityCC);
        // End
        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    //}

        // increment the feedback counter for the control channel
        qualitySequenceCounter++;
        // this code allows us to check the counter by printing it to std out
 /*       int counterCheck = *((int *)buffer);

        std::cout << "Counter check: " << counterCheck << "\n";


        const char* beg = buffer;
        const char* end = beg + sizeof(buffer);
        while(beg != end)
            std::cout << std::bitset<8>(*beg++) << ' ';
        std::cout << '\n';
  */
        // will need to reset the fileLoc counter to 0 once we reach the end of the audio file to loop the demo
    }

    //close input file
    inFile.close();

    return 0;
}