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