问题
I'm continuously sending arrays of pixel values (uint32) from LabVIEW to a C-program through TCP/IP. I'm using the recv function in Ws2_32.lib to receive the bytes, but I have to convert them back to uint32 data type and doesn't really know how to do it in this case. I'll be thankful if anyone shows how to do it.
Thanks in advance
#define DEFAULT_BUFLEN 256
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
int main(int argc , char *argv[])
{
WSADATA wsa;
SOCKET s , new_socket;
struct sockaddr_in server , client;
int c;
typedef unsigned char bytes[256];
typedef unsigned int uint32_t;
int iResult;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
return 1;
}
printf("Initialised.\n");
//Create a socket
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
}
printf("Socket created.\n");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 13000 );
//Bind
if( bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : %d" , WSAGetLastError());
}
puts("Bind done");
//Listen to incoming connections
listen(s , 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
new_socket = accept(s , (struct sockaddr *)&client, &c);
if (new_socket == INVALID_SOCKET)
{
printf("accept failed with error code : %d" , WSAGetLastError());
}
do {
iResult = recv(new_socket, recvbuf, recvbuflen, 0);
if ( iResult > 0 )
printf("%d\n", iResult);
else if ( iResult == 0 )
printf("Connection closed\n");
else
printf("recv failed: %d\n", WSAGetLastError());
}
while( iResult > 0 );
closesocket(s);
WSACleanup();
return 0;
}
回答1:
First ensure that your do while
block works as expected.
Concerning you question
As we know one dimensional array can be think as pointer to memory block. so
char *ar = recvbuf ;
char x1= *ar; //will get first byte (index 0)
char x2=*(ar+1); //will get second byte (index 1)
Also as array and pointer in our case can be used interchangeable We can access as indexed way too
char x1=ar[0];// the same as *ar
char x2=ar[1]; //= *(ar+1);
As you see char will move one byte, but in our case we want to move 4 bytes. so we will make our pointer to point to int.
int *intarr=(int *) recvbuf ; //recvbuf is address
now we can access and fetch ints using the same syntax
int x1=*intarr;
int x2= *(intarr+1); // *((int*)(ar+4))
//or
int x1=intarr[0];
And note that if inarr
point to for example to address 00004
, (inarr+1)
will point to
00004+ 4=00008th
address. Cause pointer arithmetic will know that next int address will be obtained using addr+sizeof(int)
.
Next issue. Bytes order can be different. see endianness
On that case we have to make conversion. either we will write our functions. or we can use
htonl ntohl
. Or see this manual conversion endiannes conversion on stackoverflow
Then coming to my code: uint32_t *endp=(uint32_t*)(recvbuf+iResult);
will point to end of our array. so we will increment our pointer until it be equal to endp; while(p<endp) ++p;
and simple we will use *
dereference operator to get that value. after ++p p
will point to next int block,and fetching uint32_t
from that address will be equal to *p
. And we will increment that until endp
Another option just to use index syntax. so we have to first calculate length of our array. How many ints we got in our array .this will be equal iResult/sizeof(uint32_t)
iResult our length in bytes
. After that we can access index using *(p+index)
or more nice way p[index]
...
uint32_t *p=(uint32_t*)recvbuf;
uint32_t *endp=(uint32_t*)(recvbuf+iResult);
//here is accessing
while(p<endp){
//ntohl(*p) if it was send from begin endian
uint32_t value=*p;p++;
}
//or
uint32_t *p=(uint32_t*)recvbuf;
size_t len=iResult/sizeof(uint32_t);
//
for(int i=0;i<len;i++){
uint32_t value= p[i]; //and again if there is endian problem solve it using ntonl htonl
}
回答2:
Consider the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
uint8_t char byteArray[4] = {0xBE, 0xEF, 0xFA, 0xCE};
uint32_t int32Word = *(uint32_t *)byteArray;
printf("%#X\n", int32Word);
#ifdef LITTLE_ENDIAN
int32Word = ((int32Word & 0xFF000000) >> 24) |
((int32Word & 0x00FF0000) >> 8) |
((int32Word & 0x0000FF00) << 8) |
((int32Word & 0x000000FF) << 24);
printf("%#X\n", int32Word);
#endif
system("pause");
return 0;
}
Output (My Machine is Little Endian):
0xCEFAEFBE
0xBEEFFACE
Press any key to continue . . .
If you capture 4 uint8_t
s at a time from the stream, you can convert them to an uint32_t
. Note that if your platform is little endian, you will have to do some byte rearranging.
来源:https://stackoverflow.com/questions/20755897/converting-bytes-to-uint32-in-c