计算机网络课实验(6):利用 Socket API 实现网上点对点通信。

开发环境:

操作系统:Windows 11

IDE:Visual Studio 2022

编程语言:C/C++

实验要求:

程序一“基于 TCP 的可靠文件传输”,功能包括:

  • 在客户端,用户选择本地的某个文件,并发送到服务器端。
  • 在服务器端,接收客户端传输的数据流,并按 IP 地址保存在服务器端(文件名重复的,可以覆盖)。
  • 如果传输过程中服务器端发现客户端断开,服务器端应删除文件,并在屏 幕上提示,如“IP1.2.3.4 发来 abcd.txt 文件过程中失去连接。”。
  • 如果客户端发 现服务器端不工作,客户端应有提示“服务器 1.2.3.5:62345 失去连接”。

程序二“基于 UDP 的不可靠文件传输”

  • 功能同上,但不能使用 TCP 协议进行传输。考虑如果传输过程中服务器端、客户端如何发现断开。

程序演示:

程序一:

发送中途关闭客户端

发送中途关闭服务端

程序二:

发送过程中客户端关闭

emm……UDP的客户端 判断 服务端关闭没做,客户端只管发送,才不管服务端接受没。至于服务端判断客户端失去连接,是通过接收超时判断的。

代码:

程序一Server:

#define _CRT_SECURE_NO_WARNINGS
#include <ws2tcpip.h>  
#include <stdio.h>  

#include <winsock2.h>  
#pragma comment(lib, "ws2_32.lib")  

#define DEFAULT_PORT "54321"  
#define BUFFER_SIZE 1024  

int main() {
    // 初始化库
    WSADATA wsaData;
    int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (result != 0) {
        printf("WSAStartup failed with error: %d\n", result);
        return 1;
    }

    // 创建套接字
    SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (serverSocket == INVALID_SOCKET) {
        printf("Could not create socket: %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }

    // 绑定IP和端口
    sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    serverAddr.sin_port = htons(atoi(DEFAULT_PORT));

    if (bind(serverSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
        printf("Bind failed with error: %d\n", WSAGetLastError());
        closesocket(serverSocket);
        WSACleanup();
        return 1;
    }

    // 开始监听
    if (listen(serverSocket, 5) == SOCKET_ERROR) {
        printf("Listen failed with error: %d\n", WSAGetLastError());
        closesocket(serverSocket);
        WSACleanup();
        return 1;
    }

    printf("Server listening on port %s...\n\n", DEFAULT_PORT);

    // 循环接收文件
    while (1)
    {
        SOCKADDR clientAddr;
        int clientAddrSize = sizeof(clientAddr);
        // 从已完成连接队列返回下一个建立成功的连接
        SOCKET clientSocket = accept(serverSocket, &clientAddr, &clientAddrSize);
        if (clientSocket == INVALID_SOCKET) {
            printf("Accept failed with error: %d\n", WSAGetLastError());
            closesocket(serverSocket);
            WSACleanup();
            return 1;
        }

        printf("一个客户端连接成功!\n\n");

        char buffer[BUFFER_SIZE + 1] = { 0 };

        // 接收 文件大小 和 文件名
        char fileNameAndExt[MAX_PATH * 4];
        int fileSize = 0;
        int receivedBytes = recv(clientSocket, buffer, BUFFER_SIZE, 0);
        if (receivedBytes == SOCKET_ERROR) {
            int error = WSAGetLastError();
            if (error == WSAECONNRESET) {
                printf("Client connection reset by peer.\n");
                break;
            }
            else if (error == WSAETIMEDOUT) {
                printf("Receive timeout.\n");
                break;
            }
            else {
                printf("Send failed with error: %d\n", error);
                break;
            }
        }
        else if (receivedBytes == 0) {
            printf("Connection closed by client.\n");
            break;
        }
        else {
            // 取出文件大小(前4个字节),文件名
            fileSize = (((unsigned char)buffer[0]) << 24) |
                (((unsigned char)buffer[1]) << 16) |
                (((unsigned char)buffer[2]) << 8) |
                ((unsigned char)buffer[3]);
            strcpy(fileNameAndExt, buffer + 4);
            printf("接收到文件:%s\n", fileNameAndExt);
            printf("文件大小:%d\n", fileSize);
        }

        // 打开文件,准备写入
        FILE* pFile = fopen(fileNameAndExt, "wb");
        if (pFile != NULL)
        {
            bool success = true;// 文件是否完全接收
            int receivedSize = 0;// 已接收的字节数
            // 循环接收文件,直到指定大小
            while (1)
            {
                receivedBytes = recv(clientSocket, buffer, BUFFER_SIZE, 0);
                if (receivedBytes == SOCKET_ERROR) {
                    success = false;
                    int error = WSAGetLastError();
                    if (error == WSAECONNRESET) {
                        // 连接断开:输出 客户端IP、端口,删除文件
                        char clientIP[INET_ADDRSTRLEN];
                        int clientPort;
                        struct sockaddr_in addr;
                        int addrLen = sizeof(addr);
                        if (getpeername(clientSocket, (struct sockaddr*)&addr, &addrLen) == 0)
                        {
                            inet_ntop(AF_INET, &addr.sin_addr, clientIP, INET_ADDRSTRLEN);
                            clientPort = ntohs(addr.sin_port);
                        }
                        else
                            printf("Error getting peer name: %d\n", WSAGetLastError());

                        printf("客户端 %s : %d 发来%s 文件过程中失去连接.\n", clientIP, clientPort, fileNameAndExt);
                        break;
                    }
                    else if (error == WSAETIMEDOUT) {
                        printf("Receive timeout.\n");
                        break;
                    }
                    else {
                        printf("Send failed with error: %d\n", error);
                        break;
                    }
                }
                else {
                    // 将缓冲区中的数据写入本地文件
                    if (fwrite(buffer, 1, receivedBytes, pFile) != receivedBytes)
                    {
                        printf("写入失败.\n");
                        break;
                    }

                    // 接收到指定大小,即认为文件接收成功
                    receivedSize += receivedBytes;
                    if (receivedSize == fileSize)
                    {
                        printf("%s 接收成功!\n\n\n", fileNameAndExt);
                        break;
                    }
                }
            }
            // 关闭本地文件
            fclose(pFile);

            // 文件未能接收完全,删除之
            if (!success)
            {
                remove(fileNameAndExt);
                printf("%s 已删除.\n\n\n", fileNameAndExt);
            }
        }
        else
        {
            printf("文件打开失败.\n\n\n");
        }
 
        closesocket(clientSocket);
    }

    closesocket(serverSocket);
    WSACleanup();

    system("pause");
    return 0;
}

程序一Client:

#define _CRT_SECURE_NO_WARNINGS
#include <ws2tcpip.h>  
#include <stdio.h> 

#include <winsock2.h> 
#pragma comment(lib, "ws2_32.lib")  

#define DEFAULT_PORT "54321"  
#define SERVER_IP "127.0.0.1" // 假设服务器在本地运行  
#define BUFFER_SIZE 1024  

// 这个类,是为了实现文件选择的。
class ChooseFile
{
private:
    WCHAR name[MAX_PATH];
    WCHAR ext[MAX_PATH];
    char fileName_[MAX_PATH * 2];
    char fileExt_[MAX_PATH * 2];
    int fileSize;
public:
    char fileSizeAndName[MAX_PATH * 4 + 4];
    HANDLE hFile;
    int fileNameSize;
    char fileName[MAX_PATH * 4];

    ChooseFile()
    {
        hFile = Choose(name, ext);
        ConvertWCHARtoCHAR(name, fileName_, MAX_PATH * 2);
        ConvertWCHARtoCHAR(ext, fileExt_, MAX_PATH * 2);
        strPlusStr(fileName_, fileExt_, fileName);
        fileNameSize = strlen(fileName);

        // 将filesize添加到char数组的前面
        unsigned bytes[4];
        bytes[0] = (fileSize >> 24) & 0xFF;
        bytes[1] = (fileSize >> 16) & 0xFF;
        bytes[2] = (fileSize >> 8) & 0xFF;
        bytes[3] = fileSize & 0xFF;
        strcpy(fileSizeAndName + 4, fileName);
        for (int i = 0; i < 4; i++)
        {
            fileSizeAndName[i] = bytes[i];
        }
        int temp = (bytes[0] << 24) |
            (bytes[1] << 16) |
            (bytes[2] << 8) |
            bytes[3];

        printf("文件名:%s\n", fileSizeAndName + 4);
        printf("文件大小: %d\n", fileSize);
    }

private:
    void ConvertWCHARtoCHAR(const WCHAR* src, char* dest, int destSize) {
        WideCharToMultiByte(CP_ACP, 0, src, -1, dest, destSize, NULL, NULL);
    }

    void strPlusStr(char* front, char* behind, char* dest)
    {
        // 计算合并后字符串的长度(包括结束符'\0')  
        int len1 = strlen(front);
        int len2 = strlen(behind);
        int total_len = len1 + len2 + 1; // 加1是为了结束符'\0'  

        // 将str1复制到merged_str  
        strcpy(dest, front);

        // 将str2追加到merged_str的末尾  
        strcpy(dest + len1, behind);
    }

    HANDLE Choose(WCHAR* fileName, WCHAR* fileExt)
    {
        OPENFILENAME ofn;
        ZeroMemory(&ofn, sizeof(ofn));
        ofn.lStructSize = sizeof(ofn);
        ofn.hwndOwner = NULL; // 或者设置为你的窗口句柄  
        ofn.lpstrFilter = L"Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0\0";// 设置了文件类型过滤器,允许用户选择文本文件或所有文件
        ofn.nFilterIndex = 1;
        ofn.lpstrFile = new WCHAR[MAX_PATH]; // 分配足够的空间存储文件路径  
        ZeroMemory(ofn.lpstrFile, MAX_PATH * sizeof(WCHAR)); // 确保缓冲区被清零
        ofn.nMaxFile = MAX_PATH;
        ofn.lpstrDefExt = L"txt";// 设置了默认的文件扩展名为.txt
        ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;

        if (GetOpenFileName(&ofn) == TRUE)
        {
            // 用户选择了文件,ofn.lpstrFile现在包含文件路径  
            printf("选择文件成功!\n");
            // 提取文件名和扩展名
            _wsplitpath_s(ofn.lpstrFile, NULL, 0, NULL, 0, fileName, MAX_PATH, fileExt, MAX_PATH);

            // ... 接下来读取文件内容  
            HANDLE hFile = CreateFileW(
                ofn.lpstrFile,
                GENERIC_READ,
                FILE_SHARE_READ,
                NULL,
                OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL,
                NULL);
            if (hFile != INVALID_HANDLE_VALUE)
            {
                fileSize = GetFileSize(hFile, NULL);
                return hFile;
            }
            fileSize = 0;
            return NULL;
        }
    }
};

int main() {
    char serverIP[16];
    printf("请输入 服务器IP:\n");
    scanf("%s", serverIP);

    // 初始化库
    WSADATA wsaData;
    int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (result != 0) {
        printf("WSAStartup failed with error: %d\n", result);
        return 1;
    }

    // 创建套接字
    SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (clientSocket == INVALID_SOCKET) {
        printf("Could not create socket: %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }

    // 选择 要发送的文件
    ChooseFile file;// 构造函数中,就已经选定了文件

    // 发起3次握手,连接到服务器
    sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    int addrInfoSize = sizeof(serverAddr.sin_addr);
    if (inet_pton(AF_INET, serverIP, &(serverAddr.sin_addr)) <= 0) {
        printf("Invalid address/ Address not supported \n");
        return 1;
    }
    serverAddr.sin_port = htons(atoi(DEFAULT_PORT));

    if (connect(clientSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
        printf("Connect failed with error: %d\n", WSAGetLastError());
        closesocket(clientSocket);
        WSACleanup();
        system("pause");
        return 1;
    }

    printf("成功连接到服务器!\n");

    // 发送文件大小 和 文件名
    int sentBytes = send(
        clientSocket,
        (char*)&file.fileSizeAndName,
        file.fileNameSize + 5,// 文件大小4个字节,字符串结束标志1个字节
        0);
    if (sentBytes == SOCKET_ERROR)
    {
        int error = WSAGetLastError();
        if (error == WSAECONNRESET)
        {
            char serverIP[INET_ADDRSTRLEN];
            int serverPort;
            struct sockaddr_in addr;
            int addrLen = sizeof(addr);
            if (getpeername(clientSocket, (struct sockaddr*)&addr, &addrLen) == 0)
            {
                inet_ntop(AF_INET, &addr.sin_addr, serverIP, INET_ADDRSTRLEN);
                serverPort = ntohs(addr.sin_port);
            }
            else
                printf("Error getting peer name: %d\n", WSAGetLastError());
            printf("服务器 %s : %d失去连接.\n", serverIP, serverPort);
        }
        else
            printf("Send failed with error: %d\n", error);

        // 发送失败(文件名都发送失败了,还有什么好说的,直接结束程序)
        closesocket(clientSocket);
        WSACleanup();
        system("pause");
        return 0;
    }
    else
    {
        printf("正在发送%s\n", file.fileName);
    }

    // 稍等一会,等待服务端取走缓冲区中的 文件大小 和 文件名
    Sleep(100);

    // 循环读取文件内容到缓冲区 并 发送之
    char buffer[BUFFER_SIZE];
    DWORD dwBytesRead;
    bool success = true;// 全部发送成功 标志
    while (ReadFile(file.hFile, buffer, BUFFER_SIZE, &dwBytesRead, NULL) && dwBytesRead > 0)
    {
        // 处理缓冲区中的数据,比如发送到服务器
        sentBytes = send(clientSocket, buffer, dwBytesRead, 0);
        if (sentBytes == SOCKET_ERROR) 
        {
            success = false;
            int error = WSAGetLastError();
            if (error == WSAECONNRESET) 
            {
                char serverIP[INET_ADDRSTRLEN];
                int serverPort;
                struct sockaddr_in addr;
                int addrLen = sizeof(addr);
                if (getpeername(clientSocket, (struct sockaddr*)&addr, &addrLen) == 0) 
                {
                    inet_ntop(AF_INET, &addr.sin_addr, serverIP, INET_ADDRSTRLEN);
                    serverPort = ntohs(addr.sin_port);
                }
                else 
                {
                    printf("Error getting peer name: %d\n", WSAGetLastError());
                    break;
                }
                printf("服务器 %s : %d失去连接\n", serverIP, serverPort);
                break;
            }
            else 
            {
                printf("Send failed with error: %d\n", error);
                break;
            }
        }
    }

    if (success)
        printf("文件发送成功\n\n");

    closesocket(clientSocket);
    WSACleanup();

    system("pause");
    return 0;
}

程序二Server:

#define _CRT_SECURE_NO_WARNINGS
#include <ws2tcpip.h> 
#include <stdio.h>
#include <string.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")  

#define DEFAULT_PORT "54321"  
#define MAX_LINE 100
#define BUFFER_SIZE 1024 // 定义缓冲区大小为1024字节

int main() 
{
    // Initialize Winsock
    WSADATA wsaData;
    int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (result != 0) {
        printf("WSAStartup failed with error: %d\n", result);
        return 1;
    }

    // Create a socket
    SOCKET serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (serverSocket == INVALID_SOCKET) {
        printf("Could not create socket: %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }

    // Bind the socket to the address and port
    sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    serverAddr.sin_port = htons(atoi(DEFAULT_PORT));

    if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
        printf("Error binding socket.\n");
        closesocket(serverSocket);
        WSACleanup();
        return 1;
    }

    printf("Server is listening on port %s...\n\n", DEFAULT_PORT);

    // 循环接收文件
    char buffer[BUFFER_SIZE];
    SOCKADDR clientAddr;
    int clientAddrLen = sizeof(clientAddr);
    int bytesReceived;
    int fileSize;
    char fileNameAndExt[MAX_PATH * 4];
    while (1)
    {
        // 取消超时设置,一直等待接收到 文件大小、文件名
        DWORD timeout = 0;  // 设置超时时间为0,表示取消超时设置。因为文件名和大小都还没接收到,没必要限制超时。文件本体才需要超时限制
        setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));

        // 接收 文件大小、文件名
        bytesReceived = recvfrom(
            serverSocket, buffer, BUFFER_SIZE, 0,
            &clientAddr, &clientAddrLen);
        if (bytesReceived == SOCKET_ERROR) {
            printf("Receive failed with error: %d\n", WSAGetLastError());
        }
        else {
            // 取出文件大小(前4个字节),文件名
            fileSize = (((unsigned char)buffer[0]) << 24) |
                (((unsigned char)buffer[1]) << 16) |
                (((unsigned char)buffer[2]) << 8) |
                ((unsigned char)buffer[3]);
            strcpy(fileNameAndExt, buffer + 4);
            printf("接收到文件:%s\n", fileNameAndExt);
            printf("文件大小:%d\n", fileSize);
        }

        // 设置接收超时时间为0.5秒。接收文件本体需要设置超时参数,一旦超时,即认为文件发送完全/客户端断开
        timeout = 500;  // 0.5秒
        setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));

        // 打开本地文件
        FILE* pFile = fopen(fileNameAndExt, "wb");
        if (pFile != NULL)
        {
            bool success = true;// 文件是否完全接收
            int receivedSize = 0;// 已接收的字节数
            while (1)
            {
                // Receive data from client
                bytesReceived = recvfrom(
                    serverSocket, buffer, BUFFER_SIZE, 0,
                    &clientAddr, &clientAddrLen);
                if (bytesReceived == SOCKET_ERROR) {
                    success = false;
                    int error = WSAGetLastError();
                    if (WSAGetLastError() == WSAETIMEDOUT) {
                        char clientIP[INET_ADDRSTRLEN];
                        int clientPort;
                        inet_ntop(AF_INET, &(((sockaddr_in*)&clientAddr)->sin_addr), clientIP, INET_ADDRSTRLEN);
                        clientPort = ntohs(((sockaddr_in*)&clientAddr)->sin_port);
                        printf("客户端 %s : %d 发来%s 文件过程中失去连接/接收超时.\n", clientIP, clientPort, fileNameAndExt);

                        break;
                    }
                    else {
                        printf("接收数据失败: %d\n", error);
                        break;
                    }
                }
                else
                {
                    // 将缓冲区中的数据写入本地文件
                    if (fwrite(buffer, 1, bytesReceived, pFile) != bytesReceived)
                    {
                        printf("写入失败\n");
                        break;
                    }

                    // 接收到指定大小,即认为文件接收成功
                    receivedSize += bytesReceived;
                    if (receivedSize == fileSize)
                    {
                        printf("%s 接收成功!\n\n", fileNameAndExt);
                        break;
                    }
                }
            }
            // 关闭本地文件
            fclose(pFile);

            // 文件未能接收完全,删除之
            if (!success)
            {
                remove(fileNameAndExt);
                printf("%s 已删除.\n\n", fileNameAndExt);
            }
        }
        else
        {
            printf("无法打开本地文件\n\n");
        }
    }

    closesocket(serverSocket);
    WSACleanup();

    system("pause");
    return 0;
}

程序二Client:

#define _CRT_SECURE_NO_WARNINGS
#include <ws2tcpip.h>  
#include <stdio.h>
#include <string.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")  

#define DEFAULT_PORT "54321"  
#define SERVER_IP "127.0.0.1" // 假设服务器在本地运行  
#define BUFFER_SIZE 1024  

class ChooseFile
{
private:
    WCHAR name[MAX_PATH];
    WCHAR ext[MAX_PATH];
    char fileName_[MAX_PATH * 2];
    char fileExt_[MAX_PATH * 2];
    int fileSize;
public:
    char fileName[MAX_PATH * 4];
    char fileSizeAndName[MAX_PATH * 4 + 4];
    HANDLE hFile;
    int fileNameSize;

    ChooseFile()
    {
        hFile = Choose(name, ext);
        ConvertWCHARtoCHAR(name, fileName_, MAX_PATH * 2);
        ConvertWCHARtoCHAR(ext, fileExt_, MAX_PATH * 2);
        strPlusStr(fileName_, fileExt_, fileName);
        fileNameSize = strlen(fileName);

        // 将filesize添加到char数组的前面
        unsigned bytes[4];
        bytes[0] = (fileSize >> 24) & 0xFF;
        bytes[1] = (fileSize >> 16) & 0xFF;
        bytes[2] = (fileSize >> 8) & 0xFF;
        bytes[3] = fileSize & 0xFF;
        strcpy(fileSizeAndName + 4, fileName);
        for (int i = 0; i < 4; i++)
        {
            fileSizeAndName[i] = bytes[i];
        }
        int temp = (bytes[0] << 24) |
            (bytes[1] << 16) |
            (bytes[2] << 8) |
            bytes[3];

        printf("文件名:%s\n", fileSizeAndName + 4);
        printf("文件大小: %d\n", fileSize);
    }

private:
    void ConvertWCHARtoCHAR(const WCHAR* src, char* dest, int destSize) {
        WideCharToMultiByte(CP_ACP, 0, src, -1, dest, destSize, NULL, NULL);
    }

    void strPlusStr(char* front, char* behind, char* dest)
    {
        // 计算合并后字符串的长度(包括结束符'\0')  
        int len1 = strlen(front);
        int len2 = strlen(behind);
        int total_len = len1 + len2 + 1; // 加1是为了结束符'\0'  

        // 将str1复制到merged_str  
        strcpy(dest, front);

        // 将str2追加到merged_str的末尾  
        strcpy(dest + len1, behind);
    }

    HANDLE Choose(WCHAR* fileName, WCHAR* fileExt)
    {
        OPENFILENAME ofn;
        ZeroMemory(&ofn, sizeof(ofn));
        ofn.lStructSize = sizeof(ofn);
        ofn.hwndOwner = NULL; // 或者设置为你的窗口句柄  
        ofn.lpstrFilter = L"Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0\0";// 设置了文件类型过滤器,允许用户选择文本文件或所有文件
        ofn.nFilterIndex = 1;
        ofn.lpstrFile = new WCHAR[MAX_PATH]; // 分配足够的空间存储文件路径  
        ZeroMemory(ofn.lpstrFile, MAX_PATH * sizeof(WCHAR)); // 确保缓冲区被清零
        ofn.nMaxFile = MAX_PATH;
        ofn.lpstrDefExt = L"txt";// 设置了默认的文件扩展名为.txt
        ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;

        if (GetOpenFileName(&ofn) == TRUE)
        {
            // 用户选择了文件,ofn.lpstrFile现在包含文件路径  
            printf("选择文件成功!\n");
            // 提取文件名和扩展名
            _wsplitpath_s(ofn.lpstrFile, NULL, 0, NULL, 0, fileName, MAX_PATH, fileExt, MAX_PATH);

            // ... 接下来读取文件内容  
            HANDLE hFile = CreateFileW(
                ofn.lpstrFile,
                GENERIC_READ,
                FILE_SHARE_READ,
                NULL,
                OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL,
                NULL);
            if (hFile != INVALID_HANDLE_VALUE)
            {
                fileSize = GetFileSize(hFile, NULL);
                return hFile;
            }
            fileSize = 0;
            return NULL;
        }
    }
};

int main()
{
    char serverIP[16];
    printf("请输入 服务器IP:\n");
    scanf("%s", serverIP);

    // Initialize Winsock
    WSADATA wsaData;
    int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (result != 0) {
        printf("WSAStartup failed with error: %d\n", result);
        return 1;
    }

    // Create a socket
    SOCKET clientSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (clientSocket == INVALID_SOCKET) {
        printf("Error creating socket.\n");
        WSACleanup();
        return 1;
    }

    // Set up server address
    sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    int addrInfoSize = sizeof(serverAddr.sin_addr);
    if (inet_pton(AF_INET, serverIP, &(serverAddr.sin_addr)) <= 0) {
        printf("Invalid address/ Address not supported \n");
        return 1;
    }
    serverAddr.sin_port = htons(atoi(DEFAULT_PORT));

    // 选择 要发送的文件
    ChooseFile file;// 构造函数中,就已经选定了文件

    // 发送文件名
    int bytesSent = sendto(    
        clientSocket, (char*)&file.fileSizeAndName, file.fileNameSize + 5, 0,
        (struct sockaddr*)&serverAddr, sizeof(serverAddr));
    if (bytesSent == SOCKET_ERROR)
    {
        // 发送失败(文件名都发送失败了,还有什么好说的,直接结束程序)
        printf("发送失败.\n");
        closesocket(clientSocket);
        WSACleanup();
        system("pause");
        return 0;
    }
    else
    {
        printf("正在发送%s\n", file.fileName);
    }

    // 循环读取文件内容到缓冲区 并 发送之
    char buffer[BUFFER_SIZE];
    DWORD dwBytesRead;
    bool success = true;// 全部发送成功 标志
    while (ReadFile(file.hFile, buffer, BUFFER_SIZE, &dwBytesRead, NULL) && dwBytesRead > 0)
    {
        // 处理缓冲区中的数据,比如发送到服务器
        bytesSent = sendto(
            clientSocket, buffer, dwBytesRead, 0,
            (struct sockaddr*)&serverAddr, sizeof(serverAddr));
        if (bytesSent == SOCKET_ERROR)
        {
            success = false;
            printf("Error sending data.\n");
            break;
        }
    }

    if (success)
        printf("文件发送成功\n\n");

    // Close the socket
    closesocket(clientSocket);
    WSACleanup();

    system("pause");
    return 0;
}

结语:

以上,计算机网络课程实验。

实验会在实验课当堂验收,本人第一次提前一天完成,当堂验收成功,发文以记之。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值