网络编程作业——UDP传输

UDP 编程

要求

实验一

  • 客户端和服务端交互,客户端发送信息
  • 服务端显示信息来源并且将接收到的信息回传给发送方
  • 服务端使用多线程实现并发
  • 观察在服务端启动或者不启动时,客户端运行情况

实验二

  • 客户端向服务端发送文件名
  • 客户端想服务端传输文件内容
  • 双方关闭套接字
  • 注意收发速度对文件的传输结果的影响

分析

实验一

  • 首先服务端启动
    和tcp的服务端启动类似,不过不需要listen,
    只要创建socket并且绑定端口就行。

  • 然后就是recvfrom等待客户端连接

  • 一旦客户端发送数据过来了,就创建新线程,在新线程中创建一个新的socket,绑定一个新的未被占用的端口,然后给客户端返回信息。

    //创建一个新的socket
    newsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (newsocket == INVALID_SOCKET)
    {
        cout << "Create Transfer socket failed with error: " << WSAGetLastError() << endl;
        return -1;
    }
    sockaddr_in newaddr;
    newaddr.sin_family = AF_INET;
    newaddr.sin_addr.s_addr = inet_addr(IP_ADDR);
    newaddr.sin_addr.S_un.S_addr = INADDR_ANY;
    memset(newaddr.sin_zero, 0x00, 8);

    int notfirst = 0;
    int newaddr_len = sizeof(newaddr);
    //bind socket,一个新的端口
    iResult = bind(newsocket, (struct sockaddr *)&newaddr, newaddr_len);
    if (iResult != 0)
    {
        cout << "Bind socket failed: " << WSAGetLastError() << endl;
        closesocket(newsocket);
        return -1;
    }
  • 采用循环交互,只要客户端不发送“End”,双方的通信就不会结束

  • UDP是无连接的,所以无论在服务端是否开启的情况下,客户端都能进行数据发送,因为客户根本不在乎服务端是否接受。
    在服务端没有开启的情况下,客户端不能收到服务端的返回,所以会超时错误。

实验二

  • 整个交互的过程是客户端发送文件名,服务端接受到之后,开一个新线程,创建一个新的套接字,绑定一个新的端口来进行余下的文件传输,通过给客户端返回信息来通知新的端口信息。然后,客户端发送文件长度,然后是文件内容,文件发送和接受都是循环的,直到文件传输完全成功

  • 设置了超时时间,在文件传输过程中,一旦发生问题,服务端接收不到后续信息,超时之后自动退出

//设置超时时间
    int nTimeOver = 10000;
    setsockopt(TransSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&nTimeOver, sizeof(nTimeOver));
  • 客户端也设置了超时时间,如果在发送文件结束之后,如果超时时间内没有收到服务端的确认信息就自动退出
int nTimeover = 1000;
        setsockopt(ClientSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&nTimeover, sizeof(nTimeover));
  • 关于传输时间控制,使用的是sleep()函数,在前后两次发送之间调用sleep()来降低传输速度,从而可以使得UDP报文的数据不会因为传输速度太快而淹没。
Sleep(100);

实验结果

实验一

服务端开启的时候
  • 客户端参数设置

  • 可以多次发送数据

    可以多次发送数据

  • 可以接受多个客户端的同时发送数据

服务端关闭的时候

当服务器被关闭的时候

客户端可以正常发送数据,因为UDP不需要建立连接
但是客户端是不可能接收到服务端的返回信息所以会显示错误代码10060,就是在超时时间内接受不到,停止阻塞。

实验二

短文件传输
  • 客户端参数设置

PS:
2.txt大小为94643个字节

  • 文件传输

    此时文件长度还不是很长,每次发送都能被服务端接收到,而且返回信息也是成功。
长文件传输
  • 客户端参数设置

PS:
3.pdf大小为183662个字节

  • 文件传输

可以从运行结果看出来,当文件过大的时候,容易有一部分的数据不能被接收,非常容易造成内容的丢失。
此时服务端会等到超时时间到了之后自动停止阻塞

  • 修改——控制发送速度
    在每次发送,开始下一次发送之前,调用sleep函数来降低发送速度,此时,整个文件都能被服务端正确接受。

思考总结

  1. 注意初始化,有时候没有初始化会造成很大的问题

  2. UDP发送端的发送频率如果过快,就会导致信息的淹没,接收方不能接收到完整信息

  3. UDP是不可靠传输,所以需要设置超时时间,不然容易导致程序一直等待

  4. 如果UDP发送速度过快,会导致数据的淹没,从而出错。

  5. 总的来说,可靠的传输TCP虽然设置稍微复杂,但是稳定程度,可靠程度高很多,编程的时候也不容易出现特别奇怪的问题,不可靠传输UDP,虽然看上去简单一些,但是实际编程中会遇到各种乱七八糟的问题,也更加难以调试,难以发现错误。

代码

实验一

Client

#define _WINSOCK_DEPRECATED_NO_WARNINGS

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

#pragma comment (lib,"ws2_32.lib")
#define MAX_LEN 100000
using namespace std;



int main(int argc, char * argv[])
{
    WSADATA ws;
    int iResult;
    SOCKET ClientSocket = INVALID_SOCKET;
    struct sockaddr_in Server_addr;
    int Server_len;


    //检查参数个数
    if (argc != 3)
    {
        cout << "Need enter target IP and port !" << endl;
        return -1;
    }
    int PORT = atoi(argv[2]);


    //初始化 socket
    iResult = WSAStartup(MAKEWORD(2, 2), &ws);
    if (iResult != 0)
    {
        cout << "Initiate failed with error: " << GetLastError() << endl;
        WSACleanup();
        return -1;
    }

    //创建 socket
    ClientSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (ClientSocket == INVALID_SOCKET)
    {
        cout << "Create Client socket failed with error: " << WSAGetLastError() << endl;
        WSACleanup();
        return -1;
    }


    Server_addr.sin_family = AF_INET;
    Server_addr.sin_addr.s_addr = inet_addr(argv[1]);
    Server_addr.sin_port = htons(PORT);
    memset(Server_addr.sin_zero, 0x00, 8);
    Server_len = sizeof(Server_addr);

    char data[MAX_LEN];
    cout << "########################################### Interactive Mode ############################################" << endl;
    while (TRUE)
    {
        cout << "Please enter the data to send! Enter \"End\" to close the Interactive mode" << endl;
        cin >> data;
        cout << endl;
        int len = strlen(data);
        iResult = sendto(ClientSocket, data, strlen(data), 0, (sockaddr *)&Server_addr, Server_len);
        if (iResult != strlen(data) && iResult != MAX_LEN)
        {
            cout << "Sending failed with error :" << WSAGetLastError() << endl;
            cout << "Client exit." << endl;
            closesocket(ClientSocket);
            WSACleanup();
            return -1;
        }
        else if (iResult == MAX_LEN)
        {
            cout << "Sending data buffer is already full!\n " << WSAGetLastError() << endl;

        }

        int Recv_Server_addr_len = 0;
        char recvdata[MAX_LEN];
        sockaddr_in confire_addr;

        int nTimeover = 1000;
        setsockopt(ClientSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&nTimeover, sizeof(nTimeover));


        iResult = recvfrom(ClientSocket, recvdata, MAX_LEN, 0, (sockaddr *)&Server_addr, &Server_len);
        if (iResult > 0)
        {
            recvdata[iResult] = '\0';

            cout << "Receive data from Server ( " << inet_ntoa(Server_addr.sin_addr) << " : " << Server_addr.sin_port << " ) successfully!" << endl;
            cout << "Receive Data:" << endl;
            cout << recvdata << "\n\n" << endl;
            if (strcmp(recvdata, "End") == 0)
            {
                break;
            }
        }
        else if (iResult == 0)
        {
            cout << "Connection closed!\n" << endl;
        }
        else
        {
            cout << "Receive failed with error: " << WSAGetLastError() << endl;
        }

    }
    cout << "Client exit." << endl;
    cout << "########################################### Interactive End ############################################\n" << endl;
    closesocket(ClientSocket);
    WSACleanup();
    system("pause");
    return 0;


}
Server
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <iostream>
#include <stdlib.h>
#include <stdint.h>
#include <fstream>

using namespace std;

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

#define PORT 4000
#define IP_ADDR "0.0.0.0"
#define  MAX_LEN 100000

struct inform
{
    SOCKET server;
    sockaddr_in remote;
    int remote_len;
    char *data;
};

int newport = 5000;

//多线程函数
DWORD WINAPI ClientThread(LPVOID lpparameter)
{

    int iResult = 0;
    char data[MAX_LEN];
    struct inform para = *(struct inform* ) lpparameter;

    SOCKET serSocket = (SOCKET)para.server;
    sockaddr_in remotesock = para.remote;
    int remotesock_len = para.remote_len;
    strcpy(data, para.data);
    SOCKET newsocket;
    int newsocket_len = sizeof(newsocket);
    sockaddr_in interactive;
    int interactive_len = sizeof(interactive);

    //创建一个新的socket
    newsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (newsocket == INVALID_SOCKET)
    {
        cout << "Create Transfer socket failed with error: " << WSAGetLastError() << endl;
        return -1;
    }
    sockaddr_in newaddr;
    newaddr.sin_family = AF_INET;
    newaddr.sin_addr.s_addr = inet_addr(IP_ADDR);
    newaddr.sin_port = newport++;
    newaddr.sin_addr.S_un.S_addr = INADDR_ANY;
    memset(newaddr.sin_zero, 0x00, 8);

    int notfirst = 0;
    int newaddr_len = sizeof(newaddr);
    //bind socket,一个新的端口
    iResult = bind(newsocket, (struct sockaddr *)&newaddr, newaddr_len);
    if (iResult != 0)
    {
        cout << "Bind socket failed: " << WSAGetLastError() << endl;
        closesocket(newsocket);
        return -1;
    }
    cout << "########################################### Interactive Mode ############################################\n" << endl;

    while (true)
    {
        if (notfirst)
        {
            iResult = recvfrom(newsocket, data, MAX_LEN, 0, (struct sockaddr *)&interactive, &interactive_len);

            if (iResult == SOCKET_ERROR || iResult == 0)
            {
                cout << "Receive data failed with error " << WSAGetLastError() << endl;
                closesocket(newsocket);
                return -1;

            }
            data[iResult] = '\0';
        }
        notfirst = 1;
        cout << "Receive from ( " << inet_ntoa(remotesock.sin_addr) << " :" << remotesock.sin_port << " )" << endl;
        cout << "Data: " << endl;
        cout << data << endl;

        cout << "Return Message\n" << endl;

        iResult = sendto(newsocket, data, strlen(data), 0, (sockaddr *)&remotesock, remotesock_len);
        if (iResult == SOCKET_ERROR || iResult == 0)
        {
            cout << "Return message failed with error " << WSAGetLastError() << endl;
            closesocket(newsocket);
            return -1;
        }
        if (strcmp(data, "End") == 0)
        {
            break;
        }


    }

    cout << "Return message to " << inet_ntoa(remotesock.sin_addr)<<" finished\n" << endl;
    cout << "################################################### Interactive End ###################################################\n\n" << endl;
    closesocket(newsocket);
    return 0;
}


int main(int argc, char * argv[])
{
    WSADATA ws;
    SOCKET ServerSocket = INVALID_SOCKET, ClientSocket = INVALID_SOCKET;
    sockaddr_in LocalAddr,remote_addr;

    int iResult = 0;
    int Addrlen = 0;
    HANDLE hThread = NULL;


    //Initiate 
    iResult = WSAStartup(MAKEWORD(2, 2), &ws);
    if (iResult != 0)
    {
        cout << "Initiate failed with error: " << WSAGetLastError() << endl;
        return -1;
    }

    //create socket
    ServerSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (ServerSocket == INVALID_SOCKET)
    {
        cout << "create socket failed with error: " << WSAGetLastError() << endl;
        WSACleanup();
        return -1;
    }

    LocalAddr.sin_family = AF_INET;
    LocalAddr.sin_addr.s_addr = inet_addr(IP_ADDR);
    LocalAddr.sin_port = htons(PORT);
    LocalAddr.sin_addr.S_un.S_addr = INADDR_ANY;

    memset(LocalAddr.sin_zero, 0x00, 8);


    //bind socket
    iResult = bind(ServerSocket, (struct sockaddr *)&LocalAddr, sizeof(LocalAddr));
    if (iResult != 0)
    {
        cout << "Bind socket failed: " << WSAGetLastError() << endl;
        closesocket(ServerSocket);
        WSACleanup();
        return -1;
    }

    char Recvbuf[MAX_LEN];
    int remote_len = sizeof(remote_addr);
    cout << "UDP server started up!\n" << endl;

    while (TRUE)
    {
        iResult = recvfrom(ServerSocket, Recvbuf, MAX_LEN, 0, (struct sockaddr *)&remote_addr, &remote_len);

        if (iResult == SOCKET_ERROR || iResult == 0)
        {
            cout << "Receive data failed with error " << WSAGetLastError() << endl;
            //每次如果出现任何错误,continue会回到这里,因为这个时候客户端已经关闭,就可以统一的closesocket关闭连接同时返回
            return -1;

        }
        Recvbuf[iResult] = '\0';
        struct inform para;
        para.server = ServerSocket;
        para.remote = remote_addr;
        para.remote_len = remote_len;
        para.data = Recvbuf;

        hThread = CreateThread(NULL, 0, ClientThread, (LPVOID*)&para, 0, NULL);
        if (hThread == NULL)
        {
            cout << "Create Thread failed!" << endl;
            break;
        }

        CloseHandle(hThread);

    }

    closesocket(ServerSocket);
    WSACleanup();
    system("pause");

    return 0;
}

实验二

Client
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <iostream>
#include <stdlib.h>
#include <stdint.h>
#include <fstream>
#include<io.h>
#include <stdint.h>
using namespace std;

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

using namespace std;

//缓存区长度
#define  MAX_LEN 10000

int __cdecl main(int argc, char* argv[])
{
    WSADATA ws;
    SOCKET ClientSocket = INVALID_SOCKET;
    struct sockaddr_in Server_addr,Confirm_addr;
    int iResult = 0;
    int Addrlen = 0;
    HANDLE hThread = NULL;
    char Recvbuffer[MAX_LEN + 2];


    //检查参数个数
    if (argc != 4)
    {
        cout << "Need enter target IP, port and the file name to transmit !" << endl;
        return -1;
    }
    int PORT = atoi(argv[2]);


    //初始化 socket
    iResult = WSAStartup(MAKEWORD(2, 2), &ws);
    if (iResult != 0)
    {
        cout << "Initiate failed with error: " << GetLastError() << endl;
        return -1;
    }

    //创建 socket
    ClientSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (ClientSocket == INVALID_SOCKET)
    {
        cout << "Create Client socket failed with error: " << WSAGetLastError() << endl;
        WSACleanup();
        return -1;
    }


    Server_addr.sin_family = AF_INET;
    Server_addr.sin_addr.s_addr = inet_addr(argv[1]);
    Server_addr.sin_port = htons(PORT);
    memset(Server_addr.sin_zero, 0x00, 8);
    int Server_addr_len = sizeof(Server_addr);


    char filebuf[MAX_LEN + 1];        //文件内容存储数组


    //确定文件的大小
    int len;
    FILE* fp;

    if (fp = fopen(argv[3], "r"))
    {
        fseek(fp, 0, SEEK_END);
        printf("%ld\n", ftell(fp));
        len = ftell(fp);
        fclose(fp);
    }
    else
    {
        cout << "Error to get the size of file\n" << endl;
        cout << "Client exit." << endl;
        closesocket(ClientSocket);
        WSACleanup();
        return -1;
    }



    //设置超时时间
    int nTimeOver = 10000;
    setsockopt(ClientSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&nTimeOver, sizeof(nTimeOver));


    //传输文件,先传输文件名,再传输文件长度,最后传输文件内容

    cout << "########################################## File Information ##########################################" << endl;
        int len3 = strlen(argv[3]);

        //对文件名传输进行处理
        char filename[MAX_PATH];
        int i = 0;
        for (i = 0; i < len3; i++)
        {
            filename[i] = argv[3][i];
        }
        filename[i++] = '#';
        filename[i++] = '\0';

        //传输文件名        
        iResult = sendto(ClientSocket, filename, strlen(filename), 0,(sockaddr*)&Server_addr,Server_addr_len);
        if (iResult != strlen(filename) || iResult >= MAX_PATH)
        {
            cout << "Sending filename with error :" << WSAGetLastError() << endl;
            cout << "Client exit." << endl;
            closesocket(ClientSocket);
            WSACleanup();
            return -1;
        }
        cout << "Sending filename to ( " << inet_ntoa(Server_addr.sin_addr) << " : " << Server_addr.sin_port<<" ) " << endl;

        //获取传输地址信息,端口
        sockaddr_in trans_addr;
        int trans_addr_len=sizeof(trans_addr);

        iResult = recvfrom(ClientSocket, Recvbuffer, MAX_LEN, 0, (struct sockaddr *)&trans_addr, &trans_addr_len);
        Recvbuffer[iResult] = '\0';
        if (strcmp(Recvbuffer,"Ready to receive file!")!=0)
        {
            cout << "Error: " << WSAGetLastError() << endl;
            cout << "Unable to assure the port to send file!\n" << endl;
            closesocket(ClientSocket);
            WSACleanup();
            system("pause");
            return -1;
            //break;
        }
        else
        {
            cout << "File transfer to ( " << inet_ntoa(trans_addr.sin_addr) << " : " << trans_addr.sin_port <<" ) "<< endl;
        }




        //以二进制文件形式读取文件

        ifstream sourcefile(argv[3], ios::in | ios::binary);

        int filelen = len;
        int filelen_net = htonl(filelen);


        //传输内容长度
        cout << "Sending the length of file : " << filelen << "\n" << endl;


        iResult = sendto(ClientSocket, (char*)&filelen_net, 4, 0,(sockaddr*)&trans_addr,trans_addr_len);
        if (iResult == SOCKET_ERROR)
        {
            cout << "Send file length failed with error " << WSAGetLastError() << endl;
            closesocket(ClientSocket);
            WSACleanup();
            system("pause");
            return -1;
        }


        //传输文件内容
        cout << "########################################## Sending file ##########################################" << endl;
        int left = filelen;
        int mode = 0;
        while (left > 0)
        {
            if (left > MAX_LEN)
            {
                mode = MAX_LEN;
            }
            else
            {
                mode = left;
            }
            sourcefile.read(filebuf, mode);
            iResult = sendto(ClientSocket, filebuf, mode, 0, (sockaddr*)&trans_addr, trans_addr_len);
            if (iResult == SOCKET_ERROR)
            {
                cout << "Send file content failed with error " << WSAGetLastError() << "\n" << endl;
                break;
            }
            left -= mode;
            cout << "Sending Bytes: " << mode << endl;
            Sleep(100);
        }
        sourcefile.close();
        if (left != 0)
        {
            cout << "Send file content failed with error " << WSAGetLastError() << "\n" << endl;
            cout << "Client Exit..." << endl;
            closesocket(ClientSocket);
            WSACleanup();
            system("pause");
            return -1;
        }

        //判断来自客户端的返回信息
        cout << "########################################## Confirm information ##########################################\n" << endl;
        int Confirm_addr_len = sizeof(Confirm_addr);

        iResult = recvfrom(ClientSocket, Recvbuffer, MAX_LEN, 0, (sockaddr *)&Confirm_addr, &Confirm_addr_len);
        Recvbuffer[iResult] = '\0';
        if (iResult > 0)
        {
            cout << "Receive information from server ( " << inet_ntoa(Confirm_addr.sin_addr)<<" : "<<Confirm_addr.sin_port<<" )\n" << endl;

        }

        cout << "########################################## Exit ##########################################" << endl;
    closesocket(ClientSocket);
    WSACleanup();
    system("pause");
    return 0;

}
Server
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS


#include <stdio.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <iostream>
#include <stdlib.h>
#include <stdint.h>
#include <fstream>

using namespace std;

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

#define PORT 4000
#define IP_ADDR "0.0.0.0"
#define  MAX_LEN 10000



//自己定义的结构体,用于多线程传参
struct inform
{
    SOCKET server;
    sockaddr_in remote;
    int remote_len;
    char *data;
};

int newport = 4500;
//多线程函数
DWORD WINAPI ClientThread(LPVOID lpparameter)
{
    struct inform para = *(struct inform *)lpparameter;
    int iResult = 0;
    char RecvBuffer[MAX_LEN];
    //传参处理
    SOCKET ConnectSocket = (SOCKET)para.server;
    SOCKET TransSocket = INVALID_SOCKET;
    sockaddr_in remote = para.remote;
    int remote_len = para.remote_len;
    char *data = para.data;

    int filelength = 0;
    char filename[MAX_PATH] = { 0 };

    //对于传输的文件名进行处理
    int cnt = 0;
    while (data[cnt] != '#')
    {
        filename[cnt] = data[cnt];
        cnt++;
    }
    filename[cnt] = '\0';

    char connectmessage[] = "Ready to receive file!";


    //创建一个新的socket
    TransSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (TransSocket == INVALID_SOCKET)
    {
        cout << "Create Transfer socket failed with error: " << WSAGetLastError() << endl;
        return -1;
    }



    sockaddr_in newaddr;
    newaddr.sin_family = AF_INET;
    newaddr.sin_addr.s_addr = inet_addr(IP_ADDR);
    newaddr.sin_addr.S_un.S_addr = INADDR_ANY;
    memset(newaddr.sin_zero, 0x00, 8);

    int newaddr_len = sizeof(newaddr);


    //bind socket,一个新的端口
    iResult = bind(TransSocket, (struct sockaddr *)&newaddr, newaddr_len);
    if (iResult != 0)
    {
        cout << "Bind socket failed: " << WSAGetLastError() << endl;
        closesocket(TransSocket);
        return -1;
    }

    //设置超时时间
    int nTimeOver = 10000;
    setsockopt(TransSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&nTimeOver, sizeof(nTimeOver));


    //用新的socket给client发送确认信息,后续传输用新的socket
    //如果确认失败,退出
    iResult = sendto(TransSocket, connectmessage, strlen(connectmessage), 0, (sockaddr*)&remote, remote_len);
    if (iResult == SOCKET_ERROR)
    {
        cout << "Return confirm message with error " << WSAGetLastError() << endl;
        cout << "Unable for client to transfer with a new socket." << endl;
        cout << "Exit!\n" << endl;
        closesocket(TransSocket);
        return -1;
    }

    cout << "Ready to receive file!\n" << endl;

    //接收文件长度数据
    int len_tran = 0;
    iResult = recvfrom(TransSocket, (char*)&len_tran, 4, 0, (sockaddr*)&remote, &remote_len);
    if (iResult != 4)
    {
        if (iResult == -1)
        {
            cout << "Receive failed with error " << WSAGetLastError() << endl;
            closesocket(TransSocket);
            return -1;
        }
        else
        {
            cout << "Length data is not complete. Connection closed\n" << endl;
            closesocket(TransSocket);
            return -1;
        }
    }


    int recvlen = ntohl(len_tran);
    cout << "The length of file to receive is " << recvlen << "\n" << endl;

    //创建文件
    ofstream rec_file;
    rec_file.open(filename, ios::binary);
    int left = recvlen;
    int mode = 0;
    while (left > 0)
    {
        if (left >= MAX_LEN)
        {
            mode = MAX_LEN;
        }
        else
        {
            mode = left;
        }
        iResult = recvfrom(TransSocket, RecvBuffer, mode, 0, (sockaddr*)&remote, &remote_len);;
        if (iResult == -1)
        {
            cout << "Receive failed with error " << WSAGetLastError() << endl;
            break;
        }
        else if (iResult == 0)
        {
            cout << "Receive data stopped. There " << left << " bytes unreceived" << endl;
            break;
        }
        else
        {

            rec_file.write(RecvBuffer, mode);            
            cout << "Receive data : " << iResult << " bytes" << endl;
        }

        left -= mode;
        cout << " There " << left << " bytes unreceived\n" << endl;
    }
    if (left == 0)
    {
        cout << "Receive all the data\n" << endl;
        char returnmessage[] = "OK\0";

        iResult = sendto(TransSocket, returnmessage, strlen(returnmessage), 0, (sockaddr*)&remote, remote_len);
        if (iResult == SOCKET_ERROR)
        {
            cout << "Return confirm message with error " << WSAGetLastError() << endl;
            cout << "End!\n" << endl;
            closesocket(TransSocket);
            return -1;
        }
        else
        {
            cout << "Return success!\n" << endl;
            cout << "######################################################## End ########################################################\n\n" << endl;
        }
    }
    else
    {
        cout << "File transfer is too vulnerable!\n" << endl;
        cout << "End!\n" << endl;
        closesocket(TransSocket);
        return -1;

    }
    rec_file.close();
    closesocket(TransSocket);
    return 0;
}

int main(int argc, char * argv[])
{
    WSADATA ws;
    SOCKET ServerSocket = INVALID_SOCKET, ClientSocket = INVALID_SOCKET;
    sockaddr_in LocalAddr, ClientAddr;
    int iResult = 0;
    int Addrlen = 0;
    HANDLE hThread = NULL;


    //Initiate 
    iResult = WSAStartup(MAKEWORD(2, 2), &ws);
    if (iResult != 0)
    {
        cout << "Initiate failed with error: " << WSAGetLastError() << endl;
        return -1;
    }

    //create socket
    ServerSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (ServerSocket == INVALID_SOCKET)
    {
        cout << "create socket failed with error: " << WSAGetLastError() << endl;
        WSACleanup();
        return -1;
    }

    LocalAddr.sin_family = AF_INET;
    LocalAddr.sin_addr.s_addr = inet_addr(IP_ADDR);
    LocalAddr.sin_port = htons(PORT);
    LocalAddr.sin_addr.S_un.S_addr = INADDR_ANY;
    memset(LocalAddr.sin_zero, 0x00, 8);

    //bind socket
    iResult = bind(ServerSocket, (struct sockaddr *)&LocalAddr, sizeof(LocalAddr));
    if (iResult != 0)
    {
        cout << "Bind socket failed: " << WSAGetLastError() << endl;
        closesocket(ServerSocket);
        WSACleanup();
        return -1;
    }


    cout << "UDP Server is already setup!\n" << endl;



    char Recvbuf[MAX_LEN + 1];
    int ClientAddr_len;

    sockaddr_in remote_addr;
    int remote_len = sizeof(remote_addr);
    while (TRUE)
    {
        iResult = recvfrom(ServerSocket, Recvbuf, MAX_LEN, 0, (struct sockaddr *)&remote_addr, &remote_len);

        if (iResult == SOCKET_ERROR || iResult == 0)
        {
            cout << "Receive data failed with error " << WSAGetLastError() << endl;
            //每次如果出现任何错误,continue会回到这里,因为这个时候客户端已经关闭,就可以统一的closesocket关闭连接同时返回
            continue;

        }
        Recvbuf[iResult] = '\0';
        struct inform para;
        para.server = ServerSocket;
        para.remote = remote_addr;
        para.remote_len = remote_len;
        para.data = Recvbuf;
        cout << "################################################ Connect with client ##################################################" << endl;
        cout << "IP address: " << inet_ntoa(remote_addr.sin_addr) << "  port: " << remote_addr.sin_port << endl;
        hThread = CreateThread(NULL, 0, ClientThread, (LPVOID*)&para, 0, NULL);
        if (hThread == NULL)
        {
            cout << "Create Thread failed!" << endl;
            break;
        }

        CloseHandle(hThread);

    }


    closesocket(ServerSocket);
//    closesocket(ClientSocket);
    WSACleanup();
    system("pause");

    return 0;
}

ss

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值