初识Socket编程——基于数据报套接字的服务器回射程序设计

实验四、基于数据报套接字的服务器回射程序设计

0x00 实验内容

编写一服务器程序和客户程序,要求客户每输入一行数据,服务器接收后加上 "Echo:" 后回送给客户程序,当客户输入“q”后退出。过程描述如下:

UserUDP ClientUDP ServerInput Datasendto --- recvfromrecvfrom --- sendtoOutput DataUserUDP ClientUDP Server

0x01 实现过程

实现方法

这个和 实验二 中的代码是十分相似的。

公共函数

// comm.h
// 只需在实验二的基础上加上以下函数即可

SOCKET udpServerInit(u_short port)
{
    int res = -1;
    SOCKET sock_listen;
    const int on = 1;

    // 设置地址、端口
    sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(port);

    //创建套接字
    sock_listen = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock_listen == INVALID_SOCKET)
    {
        cout << WSAGetLastError() << "Socket Error!" << endl;
        cleanUp();
        return -1;
    }

    // 设置服务器地址可重用选项
    res = setsockopt(sock_listen, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
    if (res == SOCKET_ERROR)
    {
        cout << WSAGetLastError() << "Setsockopt Error!" << endl;
        closeConn(sock_listen);
        return -1;
    }

    //绑定服务器地址
    res = bind(sock_listen, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (res == SOCKET_ERROR)
    {
        cout << WSAGetLastError() << "Bind Addr Error!" << endl;
        closeConn(sock_listen);
        return -1;
    }

    return sock_listen;
}

int udpEchoServer(SOCKET sock_conn)
{
    // 此处利用指针的移动 实现添加Echo
    int res = -1;
    char recv_data[MAXLINE] = "Echo: ";
    sockaddr_in client_addr;
    int addr_len = sizeof(sockaddr_in);

    do
    {
        // 清空缓存
        memset(recv_data + 6, 0, MAXLINE - 6);

        // 循环接收数据
        res = recvfrom(sock_conn, recv_data + 6, MAXLINE - 6, 0, (SOCKADDR *)&client_addr, &addr_len);
        if (res > 0)
        {
            cout << "The Data Received From Client Is:" << recv_data << endl;

            // 回射接收的数据
            res = sendto(sock_conn, recv_data, res + 6, 0, (SOCKADDR *)&client_addr, addr_len);
            if (res == SOCKET_ERROR)
            {
                cout << WSAGetLastError() << "Send Error!" << endl;
                res = -1;
            }
            else
            {
                cout << "The Data Sent From Server Is:" << recv_data << endl;
            }
        }
        else
        {
            cout << WSAGetLastError() << "Recvfrom Error!" << endl;
            res = -1;
        }
    } while (res > 0);

    return res;
}

SOCKET udpClientInit(char *server_ip, u_short port, sockaddr_in &server_addr, bool flag)
{
    int res = -1;
    SOCKET sock_conn;

    // 设置地址、端口
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr.S_un.S_addr = inet_addr(server_ip);

    //创建套接字
    sock_conn = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock_conn == INVALID_SOCKET)
    {
        cout << WSAGetLastError() << "Socket Error!" << endl;
        cleanUp();
        return -1;
    }

    if (flag)
    {
        // 请求连接服务器
        res = connect(sock_conn, (struct sockaddr *)&server_addr, sizeof(server_addr));
        if (res == SOCKET_ERROR)
        {
            // 连接服务器失败
            cout << WSAGetLastError() << "Connect Error!" << endl;
            closeConn(sock_conn);
            return -1;
        }
    }

    return sock_conn; //连接成功
}

int udpEchoClient(SOCKET sock_conn, SOCKADDR *server_addr, int addr_len)
{
    int res = -1;
    char send_data[MAXLINE], recv_data[MAXLINE];
    memset(send_data, 0, MAXLINE);
    memset(recv_data, 0, MAXLINE);

    while (cin.getline(send_data, MAXLINE))
    {
        // 结束
        if (*send_data == 'Q' || *send_data == 'q')
        {
            cout << "Input End!" << endl;
            return 0; // 正常退出
        }

        // 发送数据
        res = sendto(sock_conn, send_data, (int)strlen(send_data), 0, (SOCKADDR *)server_addr, addr_len);
        if (res == SOCKET_ERROR)
        {
            cout << WSAGetLastError() << "Send Data Error!" << endl;
            return -1;
        }

        cout << "The Data Sent From Client Is:" << send_data << endl;

        // 接收数据
        res = recvfrom(sock_conn, recv_data, MAXLINE, 0, nullptr, nullptr);
        if (res > 0)
        {
            cout << "The Data Received From Server Is:" << recv_data << endl;
        }
        else
        {
            cout << WSAGetLastError() << "Recv Error!" << endl;
            break;
        }

        // 清空缓存
        memset(recv_data, 0, MAXLINE);
        memset(send_data, 0, MAXLINE);
    }
    return res;
}

Server 端

// server.cpp
#include "comm.h"

int main(int argc, char *argv[])
{
    int res = -1;
    SOCKET sock_listen;

    // 启动
    res = startUp();
    if (res == -1) return -1;

    //监听
    sock_listen = udpServerInit(SEVER_PORT);
    if (sock_listen == -1) return -1;

    cout << "Server Start!" << endl;
    while (true)
    {
        // 回射 如果出错,继续其他客户端请求
        res = udpEchoServer(sock_listen);
        if (res == -1) cout << "This client error, continue another client." << endl;
    }

    closeConn(sock_listen); // 关闭监听服务
    return 0;
}

Client 端

// client.cpp
#include "comm.h"

int main()
{
    int res = -1;
    SOCKET sock_conn;
    sockaddr_in server_addr;
    char server_ip[] = "127.0.0.1";

    // 启动
    res = startUp();
    if (res == -1) return -1;

    //连接
    sock_conn = udpClientInit(server_ip, SEVER_PORT, server_addr, true);
    if (sock_conn == -1) return -1;

    // 连接服务器成功
    cout << "Client Start!" << endl;
    res = udpEchoClient(sock_conn, (SOCKADDR *)&server_addr, sizeof(sockaddr_in));
    if (res == -1) cout << "This Client Error!" << endl;

    closeConn(sock_conn); // 关闭连接
    return res;
}

0x02 一些说明

有一些地方可能实现有些问题或者说是不优雅,请初学者朋友仅参考,请大佬们批评指正。

发布了46 篇原创文章 · 获赞 53 · 访问量 8万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术工厂 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览