How to receive a struct over tcp socket and output to a file? I have a struct, which is a packet and I'm trying to send this over socket and receive it on the client side and write to the file. I'm using a void pointer as the buffer to store the file data
So far I have
struct packet {
int id;
void* data;};
I'm able to access the id, the int on the client side but when i write the data out to file. the file seems to be corrupted.
UPDATE:
The Server has a file open and will read from the file and make it into a packet and send the packet to the client.
Client will also have a file open for write, as it receives the packets it will write it out to the file.
Server Side:
current_packet = 0;
While(1)
{
struct packet *current = (packet *)malloc(packet_size+sizeof(int));
current->id = current_packet;
int read = fread(¤t->data, 1, packet_size, file);
//end of file
if(read == 0){
break;
}
int byte_write = write(conn, current,read + sizeof(int));
current_packet++;
}
Client Side
current_packet = 0;
While(1)
{
struct packet *current = (packet *)malloc(packet_size+sizeof(int));
int read = read(conn, current, packet_size + sizeof(int));
//end of file
if(read == 0){
break;
}
int byte_write = fwrite(¤t->data, 1, read - sizeof(int), file);
fflush(file);
}
struct packet *current = (packet *)malloc(packet_size+sizeof(int));
Supposed packet_size is something like
const size_t packet_size = 2048;
The code cited above might allocate something big enough to contain a packet, but the data pointer isn't initialized, and also not considered correctly in the allocation.
What I would do in your case:
Have a fixed size buffer allocated per packet like this:
struct packet {
const size_t packet_size = 2048;
int id;
std::array<unsigned char,packet_size> data;
};
Related
So I want to send a char and a const char from the tcp client to the server, but the code I have below
This is the sender
struct packet {
char caseRadio;//1byte
const char* path;//4byte
};
packet* clientPacket = new packet;
string a = "C:\\Users\\Desktop\\Project phoneedge\\ForJen";
clientPacket->caseRadio = '1';
clientPacket->path = a.c_str();
int iSend1 = send(TCPClientSocket, (char*)clientPacket, sizeof(packet), 0);
This is the reciever
struct packet {
char caseRadio;//1byte
const char* path;//4byte
};
packet* clientPacket = new packet;
int iRecv = recv(sAccecpSocket, (char*)clientPacket, sizeof(packet),0);
cout << clientPacket->caseRadio << endl;
cout << clientPacket->path << endl;
I only receive the caseRadio's 1
the path throws a Unhandled exception at 0x7A8308F0 (ucrtbased.dll) in Barebonesserver.exe:
At some point the path printed out something like this
\source\repos\Barebonesserver\Debug\Barebonesserver.exe
(this is a part of the project folder path, just how?)
Send a const char * over TCP does not make sense. A const char * is only the address of a string in the memory of the sender process. It cannot magically point to something interesting in the reader process. Furthermore, sending a struct over the network is not reliable, because different compilation options could lead to different paddings in the structures.
You need to serialize your data. A common way would be to send:
a single char for caseRadio
a 16 bit integer in network order for the size of the character string
the bytes of the character string
Sender side (tests of iSend1 omitted form brievety):
...
string a = "C:\\Users\\Desktop\\Project phoneedge\\ForJen";
int iSend1 = send(TCPClientSocket, '1', 1, 0);;
int iSend1 = send(TCPClientSocket, htons(a.size()), 2, 0);
int iSend1 = send(TCPClientSocket, a.c_str(), a.size(), 0);
Reciever side (test omitted ibidem):
char caseRadio
uint16_t size;
char *data;
int iRecv = recv(sAccecpSocket, &caseRadio, 1, 0);
int iRecv = recv(sAccecpSocket, &size, 2, 0);
size = ntohs(size); // revert to host order...
data = new char[size];
int iRecv = recv(sAccecpSocket, data, size, 0);
string a{data, size};
delete[] data;
I'm trying to implement the GoBackN ARQ for a class. I'm attempting to read a file, break it up into packets of 30 characters and then store the packets in an array of packets. All of these packets are objects of the class packet.
Currently, this code compiles and runs however when I access the array of packets, at index 0 of the array I receive the last and most recent packet. When I attempt to access index 1, I expected a different packet, however, the packets are the same in all of the indices.
Why is the data in all of my packets the same?
int numPackets = 0;
packet *packetArray[30];
void addPacket(packet *p)
{
for (int i = 0; i < 30; i++)
{
if (packetArray[i])
{
continue;
}
else
{
packetArray[i] = p;
numPackets++;
break;
}
}
}
int main(int argumentCount, char *argumentVariables[]) {
char buffer[1024];
std::ifstream infile (argumentVariables[1], std::ifstream::binary);
infile.seekg (0, infile.end);
int lengthOfFile = infile.tellg();
infile.seekg (0, infile.beg);
int iterator = 0;
while(1)
{
if (lengthOfFile > 30)
{
bzero(buffer, 1024);
infile.read(buffer, 30);
lengthOfFile -= 30;
addPacket(new packet(1, iterator, strlen(buffer), buffer));
iterator++;
}
else
{
bzero(buffer, 1024);
infile.read(buffer, 30);
addPacket(new packet(1, iterator, strlen(buffer), buffer));
break;
}
}
packet * sendpckt = packetArray[0];
sendpckt->serialize(sendPayload);
printf("%s\n", sendPayload);
infile.close();
return 0;
}
Constructor code of the class packet.
packet::packet(int t, int s, int l, char * d){
type = t;
seqnum = s;
length = l;
data = d;
}
Can you show the constructor code of class "packet". First I think you must add a '\0' in the end of buffer after the "infile.read(buffer, 30)", second check if you are copying the buffer or only the address of the buffer to a "packet" member.
I am working on firmware of an ATMEL sensor board (accelerometer and gyro)and trying to read the data in a platform in Ubuntu.
Currently the firmware is like this:
Ubuntu sends a character "D" and the firmware in response sends back 20 bytes of data that ends in "\n" then ubuntu uses serialport_read_until(fd, buff, '\n') and assumes that buff[0] is byte zero and so on.The frequency of acquisition is 200hz.
BUT using this method sometimes I receive corrupted values and it is not working well. Also there are many "Unable to write on serial port" error in ubuntu.
I have found an example code from ATMEL for the firmware and there the data is sent in different packages and continuously (without waiting for the computer to ask for it) the structure is like this:
void adv_data_send_3(uint8_t stream_num, uint32_t timestamp,
int32_t value0, int32_t value1, int32_t value2)
{
/* Define packet format with 3 data fields */
struct {
adv_data_start_t start; /* Starting fields of packet */
adv_data_field_t field [3]; /* 3 data fields */
adv_data_end_t end; /* Ending fields of packet */
} packet;
/* Construct packet */
packet.start.header1 = ADV_PKT_HEADER_1;
packet.start.header2 = ADV_PKT_HEADER_2;
packet.start.length = cpu_to_le16(sizeof(packet));
packet.start.type = ADV_PKT_DATA;
packet.start.stream_num = stream_num;
packet.start.time_stamp = cpu_to_le32(timestamp);
packet.field[0].value = cpu_to_le32(value0);
packet.field[1].value = cpu_to_le32(value1);
packet.field[2].value = cpu_to_le32(value2);
packet.end.crc = 0x00; /* Not used */
packet.end.mark = ADV_PKT_END;
/* Write packet */
adv_write_buf((uint8_t *)&packet, sizeof(packet));
}
but I don't know how I can continuously read the data that is sent in a structure like above.
Sorry if it is a trivial question. I am not a programmer but I need to solve this and I could not find a solution (that I can understand!) after searching for a couple of days.
The reading function I use in linux:
int serialport_read_until(int fd, unsigned char* buf, char until){
char b[1];
int i=0;
do {
int n = read(fd, b, 1); // read a char at a time
if( n==-1) return -1; // couldn't read
if( n==0 ) {
usleep( 1 * 1000 ); // wait 1 msec try again
continue;
}
buf[i] = b[0]; i++;
} while( b[0] != until );
buf[i] = 0; // null terminate the string
return 0;}
The new Reading Func:
// Read the header part
adv_data_start_t start;
serial_read_buf(fd, reinterpret_cast<uint8_t*>(&start), sizeof(start));
// Create a buffer for the data and the end marker
std::vector<uint8_t> data_and_end(start.length - sizeof(start));
// Read the data and end marker
serial_read_buf(fd, data_and_end.data(), data_and_end.size());
// Iterate over the data
size_t num_data_fields = (data_and_end.size() - sizeof(adv_data_end_t)) / sizeof(adv_data_field_t);
adv_data_field_t* fields = reinterpret_cast<adv_data_field_t*>(data_and_end.data());
for (size_t i = 0; i < num_data_fields; i++)
std::cout << "Field #" << (i + 1) << " = " << fields[i].value << '\n';
The data packets that are sent from the firmware:
typedef struct {
uint8_t header1; // header bytes - always 0xFF5A
uint8_t header2; // header bytes - always 0xFF5A
uint16_t length; // packet length (bytes)
uint32_t time_stamp; // time stamp (tick count)
} adv_data_start_t;
typedef struct {
int32_t value; // data field value (3 VALUES)
} adv_data_field_t;
typedef struct {
uint8_t crc; // 8-bit checksum
uint8_t mark; // 1-byte end-of-packet marker
uint16_t mark2; // 2-byte end-of-packet marker (Added to avoid data structure alignment problem)
} adv_data_end_t;
Well you have the length of the packet in the packet "header", so read the header fields (the start structure) in one read, and in a second read you read the data and the end.
If the start and end parts are the same for all packets (which I guess they are), you can easily figure out the amount of data fields after the second read.
Something like this:
// Read the header part
adv_data_start_t start;
adv_read_buf(reinterpret_cast<uint8_t*>(&start), sizeof(start));
// Create a buffer for the data and the end marker
std::vector<uint8_t> data_and_end(start.length - sizeof(start));
// Read the data and end marker
adv_read_buf(data_and_end.data(), data_and_end.size());
// Iterate over the data
size_t num_data_fields = (data_and_end.size() - sizeof(adv_data_end_t)) / sizeof(adv_data_field_t);
adv_data_end_t* fields = reinterpret_cast<adv_data_end_t*>(data_and_end.data());
for (size_t i = 0; i < num_data_fields; i++)
std::cout << "Field #" << (i + 1) << " = " << fields[i] << '\n';
Possible read_buf implementation:
// Read `bufsize` bytes into `buffer` from a file descriptor
// Will block until `bufsize` bytes has been read
// Returns -1 on error, or `bufsize` on success
int serial_read_buf(int fd, uint8_t* buffer, const size_t bufsize)
{
uint8_t* current = buffer;
size_t remaining = bufsize
while (remaining > 0)
{
ssize_t ret = read(fd, current, remaining);
if (ret == -1)
return -1; // Error
else if (ret == 0)
{
// Note: For some descriptors, this means end-of-file or
// connection closed.
usleep(1000);
}
else
{
current += ret; // Advance read-point in buffer
remaining -= ret; // Less data remaining to read
}
}
return bufsize;
}
I am trying to send large amounts of data over a socket, sometimes when I call send (on Windows) it won't send all the data I requested, as expected. So, I wrote a little function that should have solved my problems- but it's causing problems where the data isn't being sent correctly and causing the images to be corrupted. I'm making a simple chat room where you can send images (screenshots) to each other.
Why is my function not working?
How can I make it work?
void _internal_SendFile_alignment_512(SOCKET sock, BYTE *data, DWORD datasize)
{
Sock::Packet packet;
packet.DataSize = datasize;
packet.PacketType = PACKET_FILETRANSFER_INITIATE;
DWORD until = datasize / 512;
send(sock, (const char*)&packet, sizeof(packet), 0);
unsigned int pos = 0;
while( pos != datasize )
{
pos += send(sock, (char *)(data + pos), datasize - pos, 0);
}
}
My receive side is:
public override void OnReceiveData(TcpLib.ConnectionState state)
{
if (state.fileTransfer == true && state.waitingFor > 0)
{
byte[] buffer = new byte[state.AvailableData];
int readBytes = state.Read(buffer, 0, state.AvailableData);
state.waitingFor -= readBytes;
state.bw.Write(buffer);
state.bw.Flush();
if (state.waitingFor == 0)
{
state.bw.Close();
state.hFile.Close();
state.fileTransfer = false;
IPEndPoint ip = state.RemoteEndPoint as IPEndPoint;
Program.MainForm.log("Ended file transfer with " + ip);
}
}
else if( state.AvailableData > 7)
{
byte[] buffer = new byte[8];
int readBytes = state.Read(buffer, 0, 8);
if (readBytes == 8)
{
Packet packet = ByteArrayToStructure<Packet>(buffer);
if (packet.PacketType == PACKET_FILETRANSFER_INITIATE)
{
IPEndPoint ip = state.RemoteEndPoint as IPEndPoint;
String filename = getUniqueFileName("" + ip.Address);
if (filename == null)
{
Program.MainForm.log("Error getting filename for " + ip);
state.EndConnection();
return;
}
byte[] data = new byte[state.AvailableData];
readBytes = state.Read(data, 0, state.AvailableData);
state.waitingFor = packet.DataSize - readBytes;
state.hFile = new FileStream(filename, FileMode.Append);
state.bw = new BinaryWriter(state.hFile);
state.bw.Write(data);
state.bw.Flush();
state.fileTransfer = true;
Program.MainForm.log("Initiated file transfer with " + ip);
}
}
}
}
It receives all the data, when I debug my code and see that send() does not return the total data size (i.e. it has to be called more than once) and the image gets yellow lines or purple lines in it — I suspect there's something wrong with sending the data.
I mis-understood the question and solution intent. Thanks #Remy Lebeau for the comment to clarify that. Based on that, you can write a sendall() function as given in section 7.3 of http://beej.us/guide/bgnet/output/print/bgnet_USLetter.pdf
int sendall(int s, char *buf, int *len)
{
int total = 0; // how many bytes we've sent
int bytesleft = *len; // how many we have left to send
int n = 0;
while(total < *len) {
n = send(s, buf+total, bytesleft, 0);
if (n == -1) {
/* print/log error details */
break;
}
total += n;
bytesleft -= n;
}
*len = total; // return number actually sent here
return n==-1?-1:0; // return -1 on failure, 0 on success
}
You need to check the returnvalue of send(). In particular, you can't simply assume that it is the number of bytes sent, there is also the case that there was an error. Try this instead:
while(datasize != 0)
{
n = send(...);
if(n == SOCKET_ERROR)
throw exception("send() failed with errorcode #" + to_string(WSAGetLastEror()));
// adjust pointer and remaining number of bytes
datasize -= n;
data += n;
}
BTW:
Make that BYTE const* data, you're not going to modify what it points to.
The rest of your code seems too complicated, in particular you don't solve things by aligning to magic numbers like 512.
I have 1 server that's built with C++ and c sockets in Unix. The client is using QT and the socket api that comes with it.
The server sends 345 bytes of data to the client.
Sending message from server:
void Moderator::testSynch(){
int type = (int) SYNCRHONIZE_M;
//Update all connected clients with info about other clients
for(int i = 0; i<nrOfClients_; i++){
const TcpSocket &clientSocket = clients_[i].getSocket();
int clientID = clients_[i].getID();
int tempType = htonl(type);
int tempClientID = htonl(clientID);
int tempNrOfClients = htonl(funNrOfClients);
clientSocket.writeData((const char*) &tempType, sizeof(tempType));
clientSocket.writeData((const char*) &tempClientID, sizeof(tempClientID));
clientSocket.writeData((const char*) &tempNrOfClients, sizeof(tempNrOfClients));
for(int j = 0; j<nrOfClients; j++){ //Send info about connectecd clients
int tempLength = (int) clients_[j].getName().length();
int tempID = clients_[j].getID();
string tempName = clients_[j].getName();
tempID = htonl(tempID);
tempLength = htonl(tempLength);
clientSocket.writeData((const char*) &tempID, sizeof(tempID));
clientSocket.writeData((const char*) &tempLength, sizeof(tempLength));
clientSocket.writeData(tempName.c_str(), (int)tempName.length());
}
}
}
bool TcpSocket::writeData(const char* buffer, int length)const{
size_t bytesLeft = length;
ssize_t bytesWritten = 0;
while((bytesWritten = write(socketFD_, buffer, bytesLeft)) > 0){
bytesLeft -= bytesWritten;
buffer += bytesWritten;
}
return bytesLeft == 0;
}
Reading message in client:
void ChatClient::readMessage(Message &message){
if(socket_->readData((char*) &type, sizeof(type))){
if(type == SYNCRHONIZE_M){
int nrOfUsers = 0;
socket_->readData((char*) &ID_, sizeof(ID_)); //Set the client ID that server gave us
socket_->readData((char*) &nrOfUsers, sizeof(nrOfUsers));
ID_ = ntohl(ID_);
nrOfUsers = ntohl(nrOfUsers);
qDebug("%s=%d", "nrOfUsers", nrOfUsers);
message.setMessageType(SYNCRHONIZE_M);
messageOK = true;
for(int i = 0; i<nrOfUsers; i++){ //Update client with all connected users to server
int userID = 0;
int nameLength = 0;
socket_->readData((char*) &userID, sizeof(userID));
socket_->readData((char*) &nameLength, sizeof(nameLength));
userID = ntohl(userID);
nameLength = ntohl(nameLength);
if(nameLength > 0){
qDebug("%s=%d", "nameLength", nameLength);
buffer = new char[nameLength];
socket_->readData(buffer, nameLength);
message.addUser(ConnectedUser(buffer, nameLength, userID));
delete [] buffer;
}
}
}
}
}
bool TcpSocket::readData(char* buffer, int length){
int bytesLeft = length;
int bytesRead = 0;
while((bytesRead = qSocket_->read(buffer, bytesLeft)) > 0){
bytesLeft -= bytesRead;
buffer += bytesRead;
}
return bytesLeft == 0;
}
The problem i'm having is sometimes the entire message from server is not available at once.
For example, first 45 bytes is available in the client. The client then tries to read the entire message (345 bytes) which results in weird behavior. Immediately after the client is done reading the next 300 bytes becomes available.
What is the best way to send messages between sockets? Also, how can I determine if the entire message have been received?
You have some notion of a "message" that exists only in your head. Nothing in your code reflects that. If you have an application protocol that involves a "message" that is sent, then you need to write code to send a message and code to receive a message based on your protocol's definition of a message. TCP only provides streams of bytes and doesn't glue them together for the application into anything bigger than one byte.