网络大数运算之传输表达式和结果

原创 2016年08月30日 19:57:50

客户端每次可以发送一个表达式到客户端,客户端解析该表达式字符串,进行相应的运算结果求解。客户端表达式传输采用结构体,结构体定义如下:

typedefstruct node{
    char bigData1[MAX_BUF]; // Data1
    char bigData2[MAX_BUF]; // Data2
    char opera;             // 运算符
}Expression;

由于使用TCP协议进行传输,采用send()发送字符流,需要对结构体指针转化为char*,发送一个字符流。但因为结构体内存对齐原因,两个变量之间可能存在空白区,这样会造成服务端在解析该字符流的时候,会出现乱码的情况。因此使用#pragma pack(1)将对齐的字节数为1字节,这样转化为字符流时,每个变量是连续存储的。服务端也需要定义相同的结构体接收该字符流。

1. 服务端

(1) 初始化监听套接字和套接字地址,然后将监听套接字与IP地址,端口进行绑定。然后监听8888端口。

void BigIntSocket::InitBigIntSocket() {

    BigIntSocket::ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    if (ListenSocket < 0) {
        close(ListenSocket);
        err_sys("socket error");
    }
    bzero(&BigIntSocket::ServerAddr, sizeof(BigIntSocket::ServerAddr));
    BigIntSocket::ServerAddr.sin_family = AF_INET;
    BigIntSocket::ServerAddr.sin_port = htons(8888);
    BigIntSocket::ServerAddr.sin_addr.s_addr = inet_addr("192.168.59.154");

}

void BigIntSocket::Bind() {
    
    if (bind(BigIntSocket::ListenSocket, (struct sockaddr*)&BigIntSocket::ServerAddr, sizeof(BigIntSocket::ServerAddr)) < 0) 
    {
        close(ListenSocket);
        err_quit("bind error");
    }        
}

void BigIntSocket::Listen() {
    
    if (listen(BigIntSocket::ListenSocket, MAX_LINE) < 0) 
        err_quit("listen error");
} 

(2) 使用accept()等待客户端的连接。

int BigIntSocket::Accept() {

    socklen_t sock_len = sizeof(ClientAddr);
    bzero(&ClientAddr, sock_len);
    ConnectSocket = accept(BigIntSocket::ListenSocket, (struct sockaddr*)&ClientAddr, &sock_len);
    if (ConnectSocket < 0) 
        err_quit("accept error");
}

(3) 接收字符流,对Exp结构体成员进行赋值。使用Datalength1和Datalength2统计每次接收data1和data2的字符个数。每次接收时需要对Datalength1和Datalength2初始化为0,防止同一个客户端多次请求,造成字符长度的累加,使得结果错误。

void BigIntSocket::Recv() {

    memset(Recvbuf, 0, sizeof(Expression));
    memset(Exp.bigData1, 0, MAX_BUF);
    memset(Exp.bigData2, 0, MAX_BUF);
    Exp.opera = 0;
   // 长度初始化0
    Datalength1 = 0;
    Datalength2 = 0;  
    len = recv(ConnectSocket, Recvbuf, 3 * MAX_BUF, 0);// 接收字符流
    if (len < 0) 
        err_sys("recv error");
    unsigned int i;
    for (; Recvbuf[Datalength1] != '\0'; ++Datalength1) 
        Exp.bigData1[Datalength1] = Recvbuf[Datalength1];
    for (i = MAX_BUF; i < 2 * MAX_BUF && Recvbuf[i] != '\0' ; ++i) 
        Exp.bigData2[Datalength2++] = Recvbuf[i];
    
    Exp.opera = Recvbuf[2 * MAX_BUF];
    //cout << Exp.bigData1 << ' ' << Exp.bigData2 << ' ' << Exp.opera;
}

(4) 对表达式进行计算。表达式存储在服务端的Exp结构体中,初始化BigInt的两个对象b1和b2,b1和b2成员为SeqList<char>,然后将Data1和Data2 使用push_back存放到SeqList<char>中。由于Recvbuf中存的是字符,所以需要减去字符0。然后根据Exp.opera选择相应的表达式进行(这里只列举了简单的加、减、乘、除的运算)。计算完毕后,将计算结果b3复制到Sendbuf缓冲区中。

void BigIntSocket::Processing() {

    BigInt b1(MAX_BUF);
    BigInt b2(MAX_BUF);
    BigInt b3(MAX_BUF * 2);
    int i, j;

    b1.push_back(0);
    b2.push_back(0);
    for (i = Datalength1 - 1; i >= 0; --i)
        b1.push_back(Exp.bigData1[i] - '0'); 
    for (j = Datalength2 - 1; j >= 0; --j) 
        b2.push_back(Exp.bigData2[j] - '0');
  // BigInt已重载过下列运算符和赋值运算符
  switch(Exp.opera) {
        case '+':
            b3 = b1 + b2;  
            break;
        case '-':
            b3 = b1 - b2;
            break;
        case 'x':
            b3 = b1 * b2;
            break;
        case '/':
            b3 = b1 / b2;
            break;
        default:
            err_quit("no operator");
            break;
    }
    j = 0;
    memset(Sendbuf, 0, 2 * MAX_BUF); 
    for (i = b3.size() - 1; i >= 1; --i) 
        Sendbuf[j++] = b3[i] + '0';   // 转化为字符
    cout << Sendbuf << endl;
}

(5) 发送字符流到客户端。

void BigIntSocket::Send() {
    
    if (send(ConnectSocket, Sendbuf, strlen(Sendbuf), 0) < 0) 
        err_sys("send error");
}

1. 客户端

(1) 初始化套接字地址。

void BigIntSocket::InitBigIntSocket() {
    
    bzero(&BigIntSocket::ServerAddr, sizeof(BigIntSocket::ServerAddr));
    BigIntSocket::ServerAddr.sin_family = AF_INET;
    BigIntSocket::ServerAddr.sin_port = htons(8888);
    BigIntSocket::ServerAddr.sin_addr.s_addr = inet_addr("192.168.59.154");
}

(2) 发送连接请求,与服务端建立连接。

void BigIntSocket::Connect() {
    
    ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (ConnectSocket < 0) 
        err_sys("socket error");

    if (connect(ConnectSocket, (struct sockaddr*)&BigIntSocket::ServerAddr, sizeof(BigIntSocket::ServerAddr)) < 0) {
        
        close(ConnectSocket);
        err_quit("connect error");
    }
}

(3) 发送表达式字符流

void BigIntSocket::Send(const char* big1, const char* opera, const char* big2) {
    // main函数使用命令行参数接收表达式,在命令行乘号不能用’*’表示
    if (big1 && opera && big2) {
        strcpy(Exp.bigData1, big1);
        Exp.opera = *opera;
        strcpy(Exp.bigData2, big2);
    }

    if ((len = send(ConnectSocket, (char*)&Exp, sizeof(Exp), 0)) < 0) 
        err_sys("send error");
}

(4) 接收计算结果

void BigIntSocket::Recv() {
    
    if (recv(ConnectSocket, Recvbuf, len, 0) < 0) 
        err_sys("recv error");

    cout << Recvbuf << endl;
}




版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

boost::asio网络传输错误码的一些实验结果(recv error_code)

错误码很重要,可以由此判断网络连接到底发生了神马事情,从而驱动高层逻辑的行为。只有笼统的错误码判断的网络层是不够规范的,鄙人觉得有些错误码还是需要在网络层就区分开的,特此记录一些当前实验的错误码以及发...

实现逆波兰表达式(后缀表达式)的运算结果

在栈的应用中有一个最经典的例题,那就是逆波兰表达式的求值。 enum OPERATOR//定义一个枚举类型 { DATA,//数字 ADD,//下面为操作 SUB, MUL, DIV, }...

我是如何成为一名python大咖的?

人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..

【Codeforces Round 274 (Div 2)A】【暴力 水题】Expression 三个数值运算使得结果最大

A. Expression time limit per test 1 second memory limit per test 256 megabytes inpu...

动态规划-表达式得到期望结果的组成种数

【题目】 给定一个只由0(假)、1(真)、&(逻辑与)、|(逻辑或)和^(异或)五种字符组成的字符串express,再给定一个布尔值desired。返回express能有多少种组合方式,可以达到de...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)