天天看點

C++ TCP&UDP&Http的資料傳輸

**TCP與UDP差別總結:

1、TCP面向連接配接(如打電話要先撥号建立連接配接);UDP是無連接配接的,即發送資料之前不需要建立連接配接

2、TCP提供可靠的服務。也就是說,通過TCP連接配接傳送的資料,無差錯,不丢失,不重複,且按序到達;UDP盡最大努力傳遞,即不保 證可靠傳遞

3、TCP面向位元組流,實際上是TCP把資料看成一連串無結構的位元組流;UDP是面向封包的

UDP沒有擁塞控制,是以網絡出現擁塞不會使源主機的發送速率降低(對實時應用很有用,如IP電話,實時視訊會議等)

4、每一條TCP連接配接隻能是點到點的;UDP支援一對一,一對多,多對一和多對多的互動通信

5、TCP首部開銷20位元組;UDP的首部開銷小,隻有8個位元組

6、TCP的邏輯通信信道是全雙工的可靠信道,UDP則是不可靠信道**

TCP協定

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

#pragma comment(lib, "ws2_32.lib")

void Sever()
{
    WSADATA wsaData;

    char buf[] = "Server: hello, I am a server....."; 

    if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        printf("Failed to load Winsock");
        return;
    }

    //建立用于監聽的套接字
    SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);

    SOCKADDR_IN addrSrv;
    addrSrv.sin_family = AF_INET;
    addrSrv.sin_port = htons(tcp_port); //1024以上的端口号,需要設定,參考udp
    addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//這裡是接收自本機,可設定自己的需要的ip

    int retVal = bind(sockSrv, (LPSOCKADDR)&addrSrv, sizeof(SOCKADDR_IN));
    if(retVal == SOCKET_ERROR){
        printf("Failed bind:%d\n", WSAGetLastError());
        return;
    }

    if(listen(sockSrv,10) ==SOCKET_ERROR){
        printf("Listen failed:%d", WSAGetLastError());
        return;
    }

    SOCKADDR_IN addrClient;
    int len = sizeof(SOCKADDR);

    while(1)
    {
        //等待客戶請求到來  
        SOCKET sockConn = accept(sockSrv, (SOCKADDR *) &addrClient, &len);
        if(sockConn == SOCKET_ERROR){
            printf("Accept failed:%d", WSAGetLastError());
            break;
        }

        printf("Accept client IP:[%s]\n", inet_ntoa(addrClient.sin_addr));

        //發送資料,這裡可注釋掉
        int iSend = send(sockConn, buf, sizeof(buf) , 0);
        if(iSend == SOCKET_ERROR){
            printf("send failed");
            break;
        }

        char recvBuf[100];
        memset(recvBuf, 0, sizeof(recvBuf));
//      //接收資料
        recv(sockConn, recvBuf, sizeof(recvBuf), 0);
        printf("%s\n", recvBuf);

        closesocket(sockConn);
    }

    closesocket(sockSrv);
    WSACleanup();
}


void Client()
{
    //加載套接字
    WSADATA wsaData;
    char buff[1024];
    memset(buff, 0, sizeof(buff));

    if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        printf("Failed to load Winsock");
        return;
    }

    SOCKADDR_IN addrSrv;
    addrSrv.sin_family = AF_INET;
    addrSrv.sin_port = htons(tcp_port);//需要發送的port
    addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//設定要發送的ip

    //建立套接字
    SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);
    if(SOCKET_ERROR == sockClient){
        printf("Socket() error:%d", WSAGetLastError());
        return;
    }

    //向伺服器發出連接配接請求
    if(connect(sockClient, (struct  sockaddr*)&addrSrv, sizeof(addrSrv)) == INVALID_SOCKET){
        printf("Connect failed:%d", WSAGetLastError());
        return;
    }else
    {
        //接收資料,這句話注釋掉
        recv(sockClient, buff, sizeof(buff), 0);
        printf("%s\n", buff);
    }

    //發送資料
    char buffer = "hello, this is a Client....";
    send(sockClient, buffer, sizeof(buffer), 0);

    //關閉套接字
    closesocket(sockClient);
    WSACleanup();
}           

頭檔案UDP_MODE.h

#include <WINSOCK2.H>  
#include <stdio.h>  
#include "fstream"
#pragma comment(lib,"WS2_32.lib")  
#define BUF_SIZE    64 
void LoadPara();
int Client(std::string& File_Path);
int Server(std::string Sim_Name_Path);           

函數UDP_MODE.cpp

//加載參數,友善config檔案調用
char facedetectip[256];
int port_client;
int port_server;
void LoadPara()
{
    LPCWSTR strPath(TEXT("./Setting.ini"));
    LPCWSTR strTitle(TEXT("Parameter"));
    LPCWSTR strKey;

    const int BUFF_LEN = 128;//讀取字元串的緩存
    TCHAR buff[BUFF_LEN];
    int iLength = 0;

    strKey = TEXT("FaceDetectIP");//facedetectip
    GetPrivateProfileString(strTitle, strKey, L"127.0.0.1", buff, BUFF_LEN, strPath);
    iLength = WideCharToMultiByte(CP_ACP, 0, buff, -1, NULL, 0, NULL, NULL);
    WideCharToMultiByte(CP_ACP, 0, buff, -1, facedetectip, iLength, NULL, NULL);

    strKey = TEXT("port_client"); //資料庫端口号
    port_client = GetPrivateProfileInt(strTitle, strKey, 3306, strPath);

    strKey = TEXT("port_server"); //資料庫端口号
    port_server = GetPrivateProfileInt(strTitle, strKey, 3306, strPath);
}
//資料接收
int Server(std::string& File_Path)
{
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    wVersionRequested = MAKEWORD(1, 1);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0)
    {
        return -1;
    }

    if (LOBYTE(wsaData.wVersion) != 1 ||
        HIBYTE(wsaData.wVersion) != 1)
    {
        WSACleanup();
        return -1;
    }

    SOCKET sockSrv = socket(AF_INET, SOCK_DGRAM, 0);
    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    addrSrv.sin_family = AF_INET;
    addrSrv.sin_port = htons(port_client);

    bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));

    SOCKADDR_IN addrClient;
    int len = sizeof(SOCKADDR);
    char recvBuf[64];

    recvfrom(sockSrv, recvBuf, sizeof(recvBuf), 0, (SOCKADDR*)&addrClient, &len);
    File_Path = recvBuf;
    closesocket(sockSrv);
    WSACleanup();
    return 0;
}
//資料發送端
void Client(std::string Sim_Name_Path)
{
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    wVersionRequested = MAKEWORD(1, 1);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0)
    {
        return -1;
    }

    if (LOBYTE(wsaData.wVersion) != 1 ||
        HIBYTE(wsaData.wVersion) != 1)
    {
        WSACleanup();
        return -1;
    }
    SOCKET sockClient = socket(AF_INET, SOCK_DGRAM, 0);
    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr = inet_addr(facedetectip);
    addrSrv.sin_family = AF_INET;
    addrSrv.sin_port = htons(port_server);

    sendto(sockClient, Sim_Name_Path.c_str(), strlen(Sim_Name_Path.c_str()) + 1, 0,
        (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
    closesocket(sockClient);
    WSACleanup();
    return 0
}           

Http

需要安裝編譯curl:

通過curl+vs2015+openssl(vs2015必須需要這個)生成libcurl.lib

将生成的lib和include放置在配置裡,并加上Ws2_32.lib Wldap32.lib

在預定義中加上BUILDING_LIBCURL, CURL_STATICLIB

TaskHttpSender 用戶端發送

#include <string>
#include<iostream>
#include <curl/curl.h>

#pragma comment(lib, "ws2_32.lib")  
#pragma comment(lib, "wldap32.lib")  
#pragma comment(lib, "libcurl.lib") 

bool send(const std::string &file/*要儲存的檔案名*/, std::string m_url/*http位址*/)
{
    curl_global_init(CURL_GLOBAL_ALL);
    CURL* m_hCurl = curl_easy_init();
    curl_slist* pOptionList = NULL;
    pOptionList = curl_slist_append(pOptionList, "Expect:");
    curl_easy_setopt(m_hCurl, CURLOPT_HTTPHEADER, pOptionList);

    curl_httppost* pFormPost = NULL;
    curl_httppost* pLastElem = NULL;

    //上傳檔案,指定本地檔案完整路徑
    curl_formadd(&pFormPost, &pLastElem, CURLFORM_COPYNAME, "sendfile",
        CURLFORM_FILE, file.c_str(), CURLFORM_CONTENTTYPE,
        "application/octet-stream", CURLFORM_END);

    curl_formadd(&pFormPost, &pLastElem,
        CURLFORM_COPYNAME, "filename",
        CURLFORM_COPYCONTENTS, file.c_str(),
        CURLFORM_END);

    //不加一個結束的hfs服務端無法寫入檔案,一般不存在這種問題,這裡加入隻是為了測試.
    curl_formadd(&pFormPost, &pLastElem, CURLFORM_COPYNAME, "end", CURLFORM_COPYCONTENTS, "end", CURLFORM_END);
    curl_easy_setopt(m_hCurl, CURLOPT_HTTPPOST, pFormPost);
    curl_easy_setopt(m_hCurl, CURLOPT_URL, m_url.c_str());

    CURLcode res = curl_easy_perform(m_hCurl);
    if (res != CURLE_OK)
    {
        std::cout << res << std::endl;
        return false;
    }
    else
        std::cout << "success" << std::endl;
    curl_formfree(pFormPost);

    return true;
}           

TaskHttpRecver 服務端接受

#include <string>
#include <cstdio>
#include<iostream>
#include <curl/curl.h>

#pragma comment(lib, "ws2_32.lib")  
#pragma comment(lib, "wldap32.lib")  
#pragma comment(lib, "libcurl.lib") 

bool recv(std::string m_filename/*要儲存的檔案名*/, std::string m_url/*http位址*/)
{

    std::string filePath =  m_filename;
    FILE *m_fp = fopen(filePath.c_str(), "w");

    if (!m_fp)
    {
        return false;
    }
    curl_global_init(CURL_GLOBAL_ALL);
    CURL* m_hCurl = curl_easy_init();
    //設定接收資料的回調   
    curl_easy_setopt(m_hCurl, CURLOPT_URL, m_url.c_str());
    curl_easy_setopt(m_hCurl, CURLOPT_WRITEFUNCTION, DownloadCallback);
    curl_easy_setopt(m_hCurl, CURLOPT_WRITEDATA, m_fp);
    curl_easy_setopt(m_hCurl, CURLOPT_MAXREDIRS, 5);
    curl_easy_setopt(m_hCurl, CURLOPT_FOLLOWLOCATION, 1);
    CURLcode retcCode = curl_easy_perform(m_hCurl);

    if (retcCode != CURLE_OK)
        std::cout << retcCode << std::endl;
    else
        std::cout << "success" << std::endl;

    curl_easy_cleanup(m_hCurl);
    fclose(m_fp);
    m_fp = nullptr;
    return true;
}

size_t DownloadCallback(void* pBuffer, size_t nSize, size_t nMemByte, void* pParam)
{
    FILE* fp = (FILE*)pParam;
    size_t nWrite = fwrite(pBuffer, nSize, nMemByte, fp);

    return nWrite;
}
           

繼續閱讀