socket接收http请求_socket接收http请求

(15) 2024-06-07 22:01:01

简述:

在Qt里利用TCP/IP协议,socket套接字设计实现结构体的收发,类似实现简单的自定义通信协议。

描述:

发送的结构体包含帧头header(占两字节)、数据长度dataLength(占一字节)、数据my_data(不多于64字节)、校验和check_sum(前面所有数据所占字节和,本身只占一个字节)。

发送方的结构体
这里要特别注意== #pragma pack(1) ==的使用,涉及到结构体内存对齐,使用这行可以设置结构体对齐方式为1字节,这点特别重要,我在这个坑里绕了好久才走出来!!这样设置主要是因为后面要使用到结构体的大小sizeof(senddata)。

#define DATA_LEN 64 #pragma pack(1) //设置结构体为1字节对齐 typedef struct sendData { 
    uchar header[2]; //帧头(2字节) uchar才能存十六进制数 uchar dataLength; //数据个数(1字节),小于64 char my_data[DATA_LEN]; //数据(小于64字节) uchar check_sum; //校验和(1字节) 前面所有字节累加和 }senddata; #pragma pack() //结束结构体对齐设置 

注意:结构体中的数据存储最好不要用 char* 类型,在后面用到结构体强转、结构体转QByteArray数组时容易出错。转的时候可能只拷贝了char的地址,没有拷贝到数据;也有可能由于char数据长度不定,发送的时候出现问题;也有可能接收方收到解析的时候出现问题。

客户端发送:

总体思路:先封装填好帧头部分,然后从界面获取用户输入的数据,将其存进结构体my_data[ ]数组中(具体操作:获取的数据是字符串,要借助QByteArray作为中间桥梁进行转换),填好数据长度和校验和,至此要发送的结构体就封装好了。然后再将封装好的结构体转为QByteArray数组(因为传输都是Byte类型数据,直接发结构体会报错),然后由于发送的数据长度每次不同,my_data数组可能就因此没有占满,此处对校验和这个数据的放置位置有个处理细节,将其放在了my_data数据后面,下面有解释。
QString转char[ ]
char data[64]; QString str="12fff"; QByteArray ba=str.toLatin1(); char *temp=ba.data(); memcpy(data,temp,ba.length()); 
 sendData st_senddata; QByteArray get_data, sendTcpData; char *temp; QString str; //senddata.header.resize(2); st_senddata.header[0] = 0x55; //假设帧头就是0X55 0XAA st_senddata.header[1] = 0xAA; str = ui->textEdit_Send->toPlainText().toLocal8Bit(); //数据超长提醒 if(str.length() > 64) { 
    QMessageBox::information(this,tr("提示"),tr("数据长度限制为64!"),QMessageBox::Yes); ui->textEdit_Send->clear(); return; } //填好数据 get_data=(QByteArray)ui->textEdit_Send->toPlainText().toLocal8Bit(); //直接获取用户输入的同时将QString转成QByteArray temp=get_data.data(); //将QByteArray转成char* memcpy(st_senddata.my_data,temp,get_data.length()); //不拷贝内存传结构体时就只会传一个指针过去 //填好数据长度 st_senddata.dataLength = get_data.length(); //填好校验和,就是my_data长度+header两字节+datalength一字节 st_senddata.check_sum = get_data.length() + 3; //使用字节数组,将结构体转为字符数组,发送的是字符数组(数据在传输过程中都是byte类型的) //直接sizeof(senddata)内存会变小,设置了对齐方式解决,,,只给他赋予数据长度加帧头、校验和所占字节 sendTcpData.resize((get_data.length()+3)); //将封装好的结构体转为QByteArray数组,因为传输都是Byte类型 memcpy(sendTcpData.data(),&st_senddata,(get_data.length()+3)); /*因为数据长度可能没有占满64字节,校验和又是存在数据之后的,所以有一段内存可能是空的,因此此处手动 把校验和值添加在QByteArray数组最后,这样发送出去的数据就是连续的*/ sendTcpData.append(st_senddata.check_sum); //发送完整的QByteArray数组,包含所有结构体信息 socket->write(sendTcpData); ui->textEdit_Recv->insertPlainText("send:"+str+"\n"); socket->flush(); //释放socket缓存 ui->textEdit_Send->clear(); //发送出去后将发送文本清空 //释放指针、清空QByteArray数组 free(temp); temp = NULL; get_data.clear(); get_data.squeeze(); sendTcpData.clear(); sendTcpData.squeeze(); 

服务端接收:

总体思路:与发送端类似,此时收到的是QByteArray数组,需要将它再转成与发送方同样的结构体。先定义一个结构体指针,将收到的QByteArray数组强转为结构体,再利用结构体指针读取里面的值,存在新的结构体变量里,方便值的读取,最后再把结构体里的my_data数据显示在接收方的文本里。校验和的读取下面也有说明。

接收方的结构体

#define DATA_LEN 64 #pragma pack(1) //接收数据的格式 typedef struct receiveData { 
    uchar header[2]; //帧头 uchar dataLength; //数据个数(1字节),小于64 char my_data[DATA_LEN]; //数据(小于64字节) uchar check_sum; //校验和(1字节) 前面所有字节累加和 }st_receivedata; #pragma pack() 
 receiveData st_receiveTcpData, *get_Data; QByteArray buffer; QString str; //读取缓冲区数据 buffer = socket->readAll(); if(!buffer.isEmpty()) { 
    memset(&st_receiveTcpData,0,sizeof (st_receiveTcpData)); get_Data = (receiveData*)buffer.data(); //强转为结构体,需要用结构体指针接收 //读取帧头 for(int i = 0; i < sizeof (st_receiveTcpData.header); i++) { 
    st_receiveTcpData.header[i] = get_Data->header[i]; } //读取数据长度 st_receiveTcpData.dataLength = get_Data->dataLength; //读取数据 for(int i = 0; i < buffer.length() - 4; i++)//buffer的长度减去header、datalength、check_sum的长度就是数据的长度 { 
    st_receiveTcpData.my_data[i] = get_Data->my_data[i]; } //读取校验和,因为发送的时候避免my_data有空内容,所以把校验和放在了my_data后面,所以此处只 //需要读取my_data后面的值就是校验和了。 get_Data->check_sum = get_Data->my_data[buffer.length()-4]; st_receiveTcpData.check_sum = get_Data->check_sum; //将my_data数据转为QString str = QString(QLatin1String(st_receiveTcpData.my_data)); //将my_data在文本框显示 ui->textEdit_Recv->insertPlainText("receive:"+str+"\n"); //释放内存 free(get_Data); buffer.clear(); buffer.squeeze(); } 

总的来说,思路很简单,但是坑也很多,尤其是数据转换问题,稍不注意就出错。

注:
QT版本 5.9.9
编译器:MinGW 32bit
THE END

发表回复