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

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

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;
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值