If I send plain text there is no problem. Everything is ok.
However If I try to send from the C# client an image, the server receives correct bytes number, but when I save the buffer to a file (in binary mode - wb), it always has 4 bytes.
I send it by the C# client by using the function File.ReadAllBytes().
My saving code looks like
FILE * pFile;
char *buf = ReceiveMessage(s);
pFile = fopen (fileName , "wb");
fwrite(buf, sizeof(buf[0]), sizeof(buf)/sizeof(buf[0]), pFile);
fclose (pFile);
free(buf);
My receiving function looks like
static unsigned char *ReceiveMessage(int s)
{
int prefix;
recv(s, &prefix, 4, 0);
int len = prefix;
char *buffer= (char*)malloc(len + 1);
int received = 0, totalReceived = 0;
buffer[len] = '\0';
while (totalReceived < len)
{
if (len - totalReceived > BUFFER_SIZE)
{
received = recv(s, buffer + totalReceived, BUFFER_SIZE, 0);
}
else
{
received = recv(s, buffer + totalReceived, len - totalReceived, 0);
}
totalReceived += received;
}
return buffer;
}
Your C code needs to pass len back from the ReceiveMessage() function.
char *buf = ReceiveMessage(s); // buf is a char*
... sizeof(buff) // sizeof(char*) is 4 or 8
So you'll need something like
static unsigned char *ReceiveMessage(int s, int* lenOut)
{
...
*lenOut = totalReceived ;
}
You do a beginners mistake of using sizeof(buf). It doesn't return the number of bytes in the buffer but the size of the pointer (which is four or eight depending on if you run 32 or 64 bit platform).
You need to change the ReceiveMessage function to also "return" the size of the received data.
You do not get size of array by sizeof. Change to i.e.:
int len = 0;
char *buf;
buf = ReceiveMessage(s, &len);
/* then use len to calculate write length */
static unsigned char *ReceiveMessage(int s, int *len)
/* or return len and pass ptr to buf */
{
...
}
Related
Hi I wanted to proxy multicast video to unicast like udpxy does: http://www.udpxy.com, but in C#
since I could not find any suitable RTP library that I could use (they were eather too complex or I could't understand how to use them), I decided to port over one that udpxy uses rtp.c: https://github.com/pcherenkov/udpxy/blob/master/chipmunk/rtp.c
everything went fine (almost, as I didn't want to use pointers), until I wanted to translate RTP_Process to C#
RTP_Process in C
RTP_process( void** pbuf, size_t* len, int verify, FILE* log )
{
int rtp_padding = -1;
size_t front_skip = 0, back_skip = 0, pad_len = 0;
char* buf = NULL;
size_t pkt_len = 0;
assert( pbuf && len && log );
buf = *pbuf;
pkt_len = *len;
if( verify && !RTP_verify( buf, pkt_len, log ) )
return -1;
if( 0 != RTP_hdrlen( buf, pkt_len, &front_skip, log ) )
return -1;
rtp_padding = buf[0] & 0x20;
if( rtp_padding ) {
pad_len = buf[ pkt_len - 1 ];
}
back_skip += pad_len;
if( verify && (pkt_len < (front_skip + back_skip)) ) {
(void) tmfprintf( log, "RTP_process: invalid header "
"(skip [%lu] exceeds packet length [%lu])\n",
(u_long)(front_skip + back_skip), (u_long)pkt_len );
return -1;
}
/* adjust buffer/length to skip heading and padding */
/*
TRACE( (void)tmfprintf( log, "In: RTP buf=[%p] of [%lu] bytes, "
"fskip=[%ld], bskip=[%lu]\n",
(void*)buf, (u_long)pkt_len,
(u_long)front_skip, (u_long)back_skip ) );
*/
buf += front_skip;
pkt_len -= (front_skip + back_skip);
/*
TRACE( (void)tmfprintf( log, "Out RTP buf=[%p] of [%lu] bytes\n",
(void*)buf, (u_long)pkt_len ) );
*/
*pbuf = buf;
*len = pkt_len;
return 0;
}
RTP_Process in C#
public byte[] RTP_process(int verify)
{
/* process RTP package to retrieve the payload: set
* pbuf to the start of the payload area; set len to
* be equal payload's length
*
* #param pbuf address of pointer to beginning of RTP packet
* #param len pointer to RTP packet's length
* #param verify verify that it is an RTP packet if != 0
* #param log log file
*
* #return 0 if there was no error, -1 otherwise;
* set pbuf to point to beginning of payload and len
* be payload size in bytes
*/
int rtp_padding = -1;
int front_skip = 0, back_skip = 0, pad_len = 0;
int pkt_len = 0;
//assert(pbuf && len && log);
//buf = *pbuf;
pbuf = buf;
//pkt_len = *len;
len = pkt_len;
/*
if (verify != 1 && RTP_verify() != 1)
RTPOK = - 1;
if (0 != RTP_hdrlen(buf, pkt_len, front_skip)) //?????
RTPOK = - 1;
*/
rtp_padding = buf[0] & 0x20;
if (rtp_padding != -1) //???????
{
pad_len = buf[pkt_len - 1];
}
back_skip += pad_len;
if ((verify != -1) && (pkt_len < (front_skip + back_skip))) //???????
{
Console.WriteLine("RTP_process: invalid header (skip {0} exceeds packet length {1})\n", (long)(front_skip + back_skip), (long)pkt_len);
RTPOK = - 1;
}
/* adjust buffer/length to skip heading and padding */
/*
TRACE( (void)tmfprintf( log, "In: RTP buf=[%p] of [%lu] bytes, "
"fskip=[%ld], bskip=[%lu]\n",
(void*)buf, (u_long)pkt_len,
(u_long)front_skip, (u_long)back_skip ) );
*/
//buf += front_skip;
//pkt_len -= (front_skip + back_skip);
/*
TRACE( (void)tmfprintf( log, "Out RTP buf=[%p] of [%lu] bytes\n",
(void*)buf, (u_long)pkt_len ) );
*/
pbuf = buf;
len = pkt_len;
RTPOK = 0;
return pbuf;
}
here the problems started
1. buf += front_skip; complained that operator += cannot be applied to operands of type byte[] and int
then why did it work in RTP_Process in C and what is a C# equivalent of that
2. in
if (rtp_padding != -1) //???????
{
pad_len = buf[pkt_len - 1]; //There is an exeption trown: System.IndexOutOfRangeException: Index was outside the bounds of the array.
its clear that I interpreted and translated something the wrong way, but the onlything I would like to do is to get MPEG-TS frame out of RTP stream to then forward it to a TCP socket, so if anyone can suggest a better way of doing that I would love to hear it
Thanks for Anwsering and Best Regards
}
First, I suggest to read carefully RFC-3550, it has all information about RTP-packet structure (mostly you need Section #5: RTP Fixed Header and extensions).
Then you have to implement RTP_hdrlen to calculate RTP header size, it must return front_skip value as RTP header size including extensions. So, you don't have to use buf += front_skip;, RTP payload starts from byte buf[front_skip].
You have wrong packet length parameter here: int pkt_len = 0;, that's why the exception is thrown here pad_len = buf[pkt_len - 1];.
i really need your help to port this c# code to Delphi one :
public unsafe byte[] Encode(byte[] inputPcmSamples, int sampleLength, out int encodedLength)
{
if (disposed)
throw new ObjectDisposedException("OpusEncoder");
int frames = FrameCount(inputPcmSamples);
IntPtr encodedPtr;
byte[] encoded =new byte [MaxDataBytes];
int length = 0;
/* How this can be ported to delphi */
fixed (byte* benc = encoded)
{
encodedPtr = new IntPtr((void*)benc);
length = API.opus_encode(_encoder, inputPcmSamples, frames, encodedPtr, sampleLength);
}
encodedLength = length;
if (length < 0)
throw new Exception("Encoding failed - " + ((Errors)length).ToString());
return encoded;
}
The main code part that i'm looking for is :
fixed (byte* benc = encoded)
{
encodedPtr = new IntPtr((void*)benc);
/* API.opus_encode = is declared in an other Class */
length = API.opus_encode(_encoder, inputPcmSamples, frames, encodedPtr, sampleLength);
}
many thanks
You seem to want to know how to deal with the fixed block in the C#.
byte[] encoded =new byte [MaxDataBytes];
....
fixed (byte* benc = encoded)
{
encodedPtr = new IntPtr((void*)benc);
length = API.opus_encode(_encoder, inputPcmSamples, frames, encodedPtr, sampleLength);
}
This use of fixed is to pin the managed array to obtain a pointer to be passed to the unmanaged code.
In Delphi we just want an array of bytes, and a pointer to that array. That would look like this:
var
encoded: TBytes;
....
SetLength(encoded, MaxDataBytes);
....
length := opus_encode(..., Pointer(encoded), ...);
or perhaps:
length := opus_encode(..., PByte(encoded), ...);
or perhaps:
length := opus_encode(..., #encoded[0], ...);
depending on how you declared the imported function opus_encode and your preferences.
If MaxDataBytes was a small enough value for the buffer to live on the stack, and MaxDataBytes was known at compile time, then a fixed length array could be used.
I'm developing a windows store application, using C#. I would like to make TCP connection to receive images (for now) from a desktop server. the server is in C++ .
I have a client C++ to test the function and it is working perfectly. Now what i want is a similar client but in C# . I tried converting it but no luck, i tried to use the same logic but i had tons of errors and deleted everything.
Help is appreciated,thanks.
C++ Server
int size = 8192; //image size
char* bufferCMP;
bufferCMP = (char*)malloc(sizeof(char)* size);
FILE *p_file;
p_file = fopen("C:\\Program Files\\img1.png", "rb");
fread(bufferCMP, 1, size, p_file);
fclose(p_file);
int chunkcount = size / DEFAULT_BUFLEN;
int lastchunksize = size - (chunkcount * DEFAULT_BUFLEN);
int fileoffset = 0;
printf("Sending actual Chunk");
while (chunkcount > 0)
{
iResult = send(ClientSocket, bufferCMP + (fileoffset * DEFAULT_BUFLEN), DEFAULT_BUFLEN, 0);
fileoffset++;
chunkcount--;
if (iResult != DEFAULT_BUFLEN)
{
printf("Sending Buffer size <> Default buffer length ::: %d\n");
}
else
{
printf("Sending Buffer size = %d \n", iResult, fileoffset);
}
}
printf("Sending last Chunk", lastchunksize);
iResult = send(ClientSocket, bufferCMP + (fileoffset * DEFAULT_BUFLEN), lastchunksize, 0);
`
C++ Client (to be converted into C#)
int size = 8192;
int FileCounter = 0;
bool flg = true;
char * fileComplete;
char * filesizeBuffer;
FILE *temp;
int receiveBuffer = 0;
int desiredRecBuffer = size;
//int desiredRecBuffer = DEFAULT_BUFLEN ;
fileComplete = (char*)malloc(sizeof(char)* size);
while (desiredRecBuffer > 0)
{
iResult = recv(ConnectSocket, fileComplete + receiveBuffer, desiredRecBuffer, 0);
//iResult = recv( ClientSocket, fileComplete + receiveBuffer , fileSize , 0 );
if (iResult < 1)
{
printf("Reveive Buffer Error %d \n", WSAGetLastError());
}
else
{
receiveBuffer += iResult;
desiredRecBuffer = size - receiveBuffer;
printf("Reveived Data size : %d \n", desiredRecBuffer);
}
}
FILE *File = fopen("C:\\Users\\amirk_000\\Pictures\\img1b.png", "wb");
fwrite(fileComplete, 1, size, File);
//flg = true;
free(fileComplete);
fclose(File);
Full example of C# client socket is available at MSDN
Modify the given SocketSendReceive method to write the received buffer (bytesReceived array) to a file stream.
Something like the following should do it:
using (var file = File.OpenWrite("myimage.png"))
{
do
{
bytes = s.Receive(bytesReceived, bytesReceived.Length, 0);
file.Write(bytesReceived, 0, bytes);
}
while (bytes > 0);
}
I am trying to replicate behavior of a perl script in my c# code. When we convert any value into the Byte[] it should look same irrespective of the language used. SO
I have this function call which looks like this in perl:
$diag_cmd = pack("V", length($s_part)) . $s_part;
where $s_par is defined in following function. It is taking the .pds file at the location C:\Users\c_desaik\Desktop\DIAG\PwrDB\offtarget\data\get_8084_gpio.pds
$s_part =
sub read_pds
{
my $bin_s;
my $input_pds_file = $_[0];
open(my $fh, '<', $input_pds_file) or die "cannot open file $input_pds_file";
{
local $/;
$bin_s = <$fh>;
}
close($fh);
return $bin_s;
}
My best guess is that this function is reading the .pds file and turning it into a Byte array.
Now, I tried to replicate the behavior into c# code like following
static byte[] ConstructPacket()
{
List<byte> retval = new List<byte>();
retval.AddRange(System.IO.File.ReadAllBytes(#"C:\Users\c_desaik\Desktop\DIAG\PwrDB\offtarget\data\get_8084_gpio.pds"));
return retval.ToArray();
}
But the resulting byte array does not look same. Is there any special mechanism that I have to follow to replicate the behavior of pack("V", length($s_part)) . $s_part ?
As Simon Whitehead mentioned the template character V tells pack to pack your values into unsigned long (32-bit) integers (in little endian order). So you need to convert your bytes to a list (or array) of unsigned integers.
For example:
static uint[] UnpackUint32(string filename)
{
var retval = new List<uint>();
using (var filestream = System.IO.File.Open(filename, System.IO.FileMode.Open))
{
using (var binaryStream = new System.IO.BinaryReader(filestream))
{
var pos = 0;
while (pos < binaryStream.BaseStream.Length)
{
retval.Add(binaryStream.ReadUInt32());
pos += 4;
}
}
}
return retval.ToArray();
}
And call this function:
var list = UnpackUint32(#"C:\Users\c_desaik\Desktop\DIAG\PwrDB\offtarget\data\get_8084_gpio.pds");
Update
If you wanna read one length-prefixed string or a list of them, you can use this function:
private string[] UnpackStrings(string filename)
{
var retval = new List<string>();
using (var filestream = System.IO.File.Open(filename, System.IO.FileMode.Open))
{
using (var binaryStream = new System.IO.BinaryReader(filestream))
{
var pos = 0;
while ((pos + 4) <= binaryStream.BaseStream.Length)
{
// read the length of the string
var len = binaryStream.ReadUInt32();
// read the bytes of the string
var byteArr = binaryStream.ReadBytes((int) len);
// cast this bytes to a char and append them to a stringbuilder
var sb = new StringBuilder();
foreach (var b in byteArr)
sb.Append((char)b);
// add the new string to our collection of strings
retval.Add(sb.ToString());
// calculate start position of next value
pos += 4 + (int) len;
}
}
}
return retval.ToArray();
}
pack("V", length($s_part)) . $s_part
which can also be written as
pack("V/a*", $s_part)
creates a length-prefixed string. The length is stored as a 32-bit unsigned little-endian number.
+----------+----------+----------+----------+-------- ...
| Length | Length | Length | Length | Bytes
| ( 7.. 0) | (15.. 8) | (23..16) | (31..24) |
+----------+----------+----------+----------+-------- ...
This is how you recreate the original string from the bytes:
Read 4 bytes
If using a machine other than a little-endian machine,
Rearrange the bytes into the native order.
Cast those bytes into an 32-bit unsigned integer.
Read a number of bytes equal to that number.
Convert that sequences of bytes into a string.
Some languages provide tools that perform more than one of these steps.
I don't know C#, so I can't write the code for you, but I can give you an example in two other languages.
In Perl, this would be written as follows:
sub read_bytes {
my ($fh, $num_bytes_to_read) = #_;
my $buf = '';
while ($num_bytes_to_read) {
my $num_bytes_read = read($fh, $buf, $num_bytes_to_read, length($buf));
if (!$num_bytes_read) {
die "$!\n" if !defined($num_bytes_read);
die "Premature EOF\n";
}
$num_bytes_to_read -= $num_bytes_read;
}
return $buf;
}
sub read_uint32le { unpack('V', read_bytes($_[0], 4)) }
sub read_pstr { read_bytes($_[0], read_uint32le($_[0])) }
my $str = read_pstr($fh);
In C,
int read_bytes(FILE* fh, void* buf, size_t num_bytes_to_read) {
while (num_bytes_to_read) {
size_t num_bytes_read = fread(buf, 1, num_bytes_to_read, fh);
if (!num_bytes_read)
return 0;
num_bytes_to_read -= num_bytes_read;
buf += num_bytes_read;
}
return 1;
}
int read_uint32le(FILE* fh, uint32_t* p_i) {
int ok = read_bytes(fh, p_i, sizeof(*p_i));
if (!ok)
return 0;
{ /* Rearrange bytes on non-LE machines */
const char* p = (char*)p_i;
*p_i = ((((p[3] << 8) | p[2]) << 8) | p[1]) << 8) | p[0];
}
return 1;
}
char* read_pstr(FILE* fh) {
uint32_t len;
char* buf = NULL;
int ok;
ok = read_uint32le(fh, &len);
if (!ok)
goto ERROR;
buf = malloc(len+1);
if (!buf)
goto ERROR;
ok = read_bytes(fh, buf, len);
if (!ok)
goto ERROR;
buf[len] = '\0';
return buf;
ERROR:
if (p)
free(p);
return NULL;
}
char* str = read_pstr(fh);
Sorry for probably simple question but I'm newbie in shared memory and trying to learn by example how to do things.
On c++ side I receive such pair: const unsigned char * value, size_t length
On c# side I need to have regular c# string. Using shared memory what is the best way to do that?
It's not that easy to using the string.
If it's me, I'll try these ways:
1.simply get a copy of the string. System.Text.Encoding.Default.GetString may convert from a byte array to a string.
You may try in a unsafe code block (for that you could use pointer type) to do:
(1) create a byte array, size is your "length"
byte[] buf = new byte[length];
(2) copy your data to the array
for(int i = 0; i < length; ++i) buf[i] = value[i];
(3) get the string
string what_you_want = System.Text.Encoding.Default.GetString(buf);
2.write a class, having a property "string what_you_want", and each time you access it, the above process will perform.
before all, you should first using P/Invoke feature to get the value of that pair.
edit: this is an example.
C++ code:
struct Pair {
int length;
unsigned char value[1024];
};
#include <windows.h>
#include <stdio.h>
int main()
{
const char* s = "hahaha";
HANDLE handle = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(Pair), L"MySharedMemory");
struct Pair* p = (struct Pair*) MapViewOfFile(handle, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(Pair));
if (p != 0) {
p->length = lstrlenA(s);
lstrcpyA((char*)p->value, s);
puts("plz start c# program");
getchar();
} else
puts("create shared memory error");
if (handle != NULL)
CloseHandle(handle);
return 0;
}
and C# code:
using System;
using System.IO.MemoryMappedFiles;
class Program
{
static void Main(string[] args)
{
MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("MySharedMemory");
MemoryMappedViewStream mmfvs = mmf.CreateViewStream();
byte[] blen = new byte[4];
mmfvs.Read(blen, 0, 4);
int len = blen[0] + blen[1] * 256 + blen[2] * 65536 + blen[3] * 16777216;
byte[] strbuf = new byte[len];
mmfvs.Read(strbuf, 0, len);
string s = System.Text.Encoding.Default.GetString(strbuf);
Console.WriteLine(s);
}
}
just for example.
you may also add error-check part.