【深圳大学计算机网络】实验四 MFC+Winsock网络编程设计报告

本文介绍了使用C++设计的点对点聊天室程序,通过TCP协议实现客户端与服务器的通信,包括流式套接字和网络事件处理。还探讨了UDP协议的实现和特点,适用于实时应用但不保证消息可靠性。
摘要由CSDN通过智能技术生成

实验目的

1. 设计一个简单的聊天室程序采用客户/服务器模式,分为客户端程序和服务器端程序。由于服务器只能支持一个客户,实际上是一个点对点通信的程序。客户端程序和服务器程序通过网络交换聊天字符串内容,并在窗口的列表框中显示。

2. 通过网络编程实践,使自己理解并掌握传输层协议基本工作原理及过程,特别是TCP协议的程序设计流程,重点学习流式套接字对象的使用和处理网络事件的方法,以及协议的封装方法。

3. 掌握Windows系统下的窗口编程方法,按照下面图的窗口设计界面,利用校园网络环境进行测试和验证。

4. 设计扩展,在聊天界面设计基础上,增加文件传输功能,实现双方的的文件发送和接收功能。

实验环境

Windows操作系统、校园网环境

实验内容

聊天室程序的功能需求如下:

(1)由两个程序组成:服务器程序(Server)和客户端程序(Client)。首先需要启动服务器,再启动客户端,并登录服务器(需指定服务器IP地址以便与服务器建立连接)。登录成功后,客户端和服务器之间可以在自己的界面上直接与对方进行聊天。

窗口界面如图所示

(2)在客户端界面增添“本机网络配置信息”按钮,点击显示本机网络配置信息(如同ipconfig命令),通过调用gethostbyname()函数获取信息。

(3)尝试改用UDP协议实现上述设计,设计流程和代码如何修改,分析其特点和应用场景,在报告中给出说明。

实验步骤

1.设置服务端程序

2.设置客户端程序

3.首先运行服务端程序

服务端程序在等待客户端进行连接。

4.运行客户端程序

5.在客户端输入消息发送

6.发现服务端收到消息

7.在服务端输入回复消息

8.发现在客户端收到回复消息

若要将TCP改为UDP实现聊天功能,需要进行以下修改:

1.在服务器端,创建的套接字类型需要改为SOCK_DGRAM,同时监听和接收连接的函数listen()和accept()也需要删除,因为UDP是无连接的,不需要进行监听和接收连接。发送消息使用sendto()函数,接收消息使用recvfrom()函数。

2.在客户端,创建的套接字类型也需要改为SOCK_DGRAM,连接函数connect()需要删除,因为UDP是无连接的,也不需要连接服务端。发送消息使用sendto()函数,接收消息使用recvfrom()函数。

特点和应用场景:

UDP协议的特点是不可靠、无连接和简单。由于UDP不需要建立连接,因此通信的开销较小,且无需等待对方回复确认,因此传输速度较快。但是由于UDP无法保证消息的可靠性,因此在传输过程中可能会丢失部分消息或重复传输部分消息,需要在应用层进行处理。

UDP协议适用于实时传输数据的场景,例如视频、音频等实时应用,因为这些应用对数据的实时性要求高,而对数据的可靠性要求不高。此外,UDP还适用于需要广播或多播的应用场景,例如在线游戏中的广播消息、网络会议中的多人会议等。

但是,由于UDP协议无法保证消息的可靠性,因此在一些对数据可靠性要求较高的场景中,如文件传输、邮件发送等应用中,通常会选择使用TCP协议。

server.cpp

// 引入头文件
#include <iostream>
#include <winsock2.h>

// 链接Winsock库
#pragma comment(lib, "ws2_32.lib")

using namespace std;

int main()
{
    // 定义变量
    WSADATA wsaData;
    SOCKET serverSocket, clientSocket;
    SOCKADDR_IN serverAddr, clientAddr;
    int clientAddrLen = sizeof(clientAddr);
    char buffer[1024];

    // 初始化Winsock库
    WSAStartup(MAKEWORD(2, 2), &wsaData);

    // 创建套接字
    serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    // 绑定服务器地址和端口
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(12345);  // 端口号为12345
    serverAddr.sin_addr.s_addr = INADDR_ANY;  // IP地址为本机地址
    bind(serverSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr));

    // 监听客户端连接
    listen(serverSocket, 1);

    // 等待客户端连接
    cout << "等待客户端连接..." << endl;
    clientSocket = accept(serverSocket, (SOCKADDR*)&clientAddr, &clientAddrLen);

    // 接收和发送消息
    while (true)
    {
        // 接收消息
        memset(buffer, 0, sizeof(buffer));
        int len = recv(clientSocket, buffer, sizeof(buffer), 0);  // 接收消息
        if (len > 0)
        {
            cout << "客户端: " << buffer << endl;  // 输出客户端发送的消息
        }

        // 发送消息
        memset(buffer, 0, sizeof(buffer));
        cout << "请输入回复消息:";
        cin.getline(buffer, sizeof(buffer));  // 输入回复消息
        send(clientSocket, buffer, strlen(buffer), 0);  // 发送回复消息
    }

    // 关闭套接字
    closesocket(serverSocket);
    closesocket(clientSocket);

    // 释放Winsock库
    WSACleanup();

    return 0;
}

 client.cpp

#include <iostream>
#include <winsock2.h>

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

using namespace std;

int main()
{
    WSADATA wsaData; // 声明WSADATA结构体,保存Winsock库初始化的信息
    SOCKET clientSocket; // 声明客户端套接字
    SOCKADDR_IN serverAddr; // 声明服务端地址结构体
    char buffer[1024]; // 声明缓冲区,用于发送和接收消息

    // Initialize Winsock library
    WSAStartup(MAKEWORD(2, 2), &wsaData); // 初始化Winsock库,版本号为2.2,将初始化信息保存在wsaData中

    // Create socket
    clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // 创建TCP套接字

    // Connect to server
    serverAddr.sin_family = AF_INET; // 地址族为IPv4
    serverAddr.sin_port = htons(12345); // 连接的端口号为12345
    serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 连接的IP地址为本地IP地址
    connect(clientSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)); // 连接服务端

    // Send and receive messages
    while (true)
    {
        // Send message
        memset(buffer, 0, sizeof(buffer)); // 将缓冲区清零
        cout << "Please enter a message: ";
        cin.getline(buffer, sizeof(buffer)); // 读入用户输入的消息
        send(clientSocket, buffer, strlen(buffer), 0); // 发送消息到服务端

        // Receive message
        memset(buffer, 0, sizeof(buffer)); // 将缓冲区清零
        int len = recv(clientSocket, buffer, sizeof(buffer), 0); // 接收服务端发来的消息
        if (len > 0)
        {
            cout << "Server: " << buffer << endl; // 输出服务端发送的消息
        }
    }

    // Close socket
    closesocket(clientSocket); // 关闭客户端套接字

    // Clean up Winsock library
    WSACleanup(); // 释放Winsock库

    return 0;
}

实验结果

运用c++完成了服务端和客户端的设计和编程实现,成功实现了进行二者的聊天发送和接收消息。

实验小结

通过网络编程实践,理解并掌握了传输层协议基本工作原理及过程,以及TCP协议的程序设计流程,流式套接字对象的使用和处理网络事件的方法,以及协议的封装方法。

(ps.由于当时还未学过java以及框架知识,因此未实现图形化界面)

(by 归忆)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

归忆_AC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值