Transfer file through text on sockets. [C# and Python] - c#

I'm currently working on a project that include file transferring. The way I originally planned it was to read it in python via
f = open(filename)
f.read()
and write it in C# using the File object interface, and the same from C#, I'm reading it through
File.ReadAllText(file)
and saving it in python.
It is transferred via sockets.
For some reason, it keeps corrupting the files. Even though the sending is perfectly fine(I checked it a thousand times), the files is read and written properly, so I'm looking for information about how to read a file through text(only text) and not having it corrupted. Any help is welcome, thanks.
Networking(Python):
def send(msg, sock):
msg = msg.__repr__()
size_of_package = sys.getsizeof(msg)
package = str(size_of_package)+":"+ msg
sock.send(package)
def recv(sock):
try:
header = sock.recv(2)
while ":" not in header:
header += sock.recv(2)
size_of_package, separator, message_fragment = header.partition(":")
message = ""
while len(message) < int(size_of_package) - len(message_fragment):
recvsize = int(size_of_package) - len(message_fragment) - len(message)
if recvsize > 2048:
recvsize = 2048
message+=sock.recv(recvsize)
full_message = message_fragment + message
return full_message
except OverflowError:
return "OverflowError."
except:
print "Unexpected error:", sys.exc_info()[0]
raise
Networking C#:
private void Send(string st)
{
int size = Encoding.ASCII.GetByteCount(st);
string pack = size + ":" + st;
buffer = Encoding.ASCII.GetBytes(pack);
connection.Send(buffer);
MessageBox.Show(buffer.Length.ToString());
}
private string Recv()
{
try
{
buffer = new byte[2];
connection.Receive(buffer, 2, SocketFlags.Partial);
string header = Encoding.ASCII.GetString(buffer, 0, 2);
while (!header.Contains(":"))
{
connection.Receive(buffer, 2, SocketFlags.Partial);
header += Encoding.ASCII.GetString(buffer, 0, 2);
}
int size = int.Parse(header.Split(':')[0]);
string mes0 = header.Split(':')[1];
buffer = new byte[size];
connection.Receive(buffer, size, SocketFlags.Partial);
string fullmes = mes0 + Encoding.ASCII.GetString(buffer);
return fullmes;
}
catch(Exception e)
{
MessageBox.Show(e.ToString());
}
return "";
}
File saving (Python)
class fileSaver:
def __init__(self , fileInf):
self.fileInf = fileInf
self.file = open(BASE_PATH+fileInf.getPath(), "wb")
self.file.write(fileInf.getContent())
self.file.close()
where fileInf is an object that contains all the info, including content, etc.
File loading(C#):
StreamReader sr = new StreamReader(file);
networking.Upload(file.Substring(file.LastIndexOf('/')+1), basepath, sr.ReadToEnd());
sr.Close();

Related

Can I use part of a Shell Object parsing name in the windows portable device (WPD) api to get a file stream?

Is it always valid to use the first part of the last guid from a windows api codepack ShellObject parsing name representing a path to a USB-connected android or iphone device when transferring a file to local storage in the windows portable device (WPD) api?
Eg. an example parsing name from a ShellObject get parsing name call:
::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy322kldjb#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\{00000009-0001-0001-0000-000000000000}\{00000009-0001-0001-0000-000000000000}\{00005461-0001-0001-0000-000000000000}
As far as I can tell, this represents:
- My Computer ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\
- USB device \\?\usb#vid_22b8&pid_2e82#zy322kldjb#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\
- Root folder SID-{10001,,26401026048}\
- Folder 1 {00000009-0001-0001-0000-000000000000}\
- Folder 2 {00000075-0001-0001-0000-000000000000}\
- File {00005461-0001-0001-0000-000000000000}
Enumerating the contents of Folder 2 on the device using the WPD api, I can see the same file has a file id like o5461 - this looks like part of the File part above.
Is this assumption always correct - can I always use it like in the following code, to copy one file from an android phone to local storage on the c-drive? Or is there sometimes a mismatch? Also, what does the "o" mean in the file id?
This seems to work, but I'm hesitant to use it in production-ready code.
using System.IO;
using PortableDeviceApiLib;
public class Copier
{
public void PerformCopy()
{
var deviceId = #"\\?\usb#vid_22b8&pid_2e82#zy322kldjb#{6ac27878-a6fa-4155-ba85-f98f491d4f33}";
var sourceItemGuidString = "{00005461-0001-0001-0000-000000000000}";
var destinationPath = #"C:\Test\";
var fileName = "Testing.jpg";
var size = 3738545;
// get "o5461" from the parsing path from the Shell libraries
var fileId = "o" + sourceItemGuidString.Replace("{", string.Empty).Replace("}", string.Empty).Split('-')[0].TrimStart('0');
this.TransferContentFromDevice(deviceId, fileId, size, destinationPath, fileName);
}
private void TransferContentFromDevice(string deviceId, string fileId, long length, string saveToPath, string fileName)
{
PortableDeviceClass device;
try
{
device = SomehowGetOnePortableDeviceAndConnectToIt(deviceId);
// Make sure that the target dir exists.
Directory.CreateDirectory(saveToPath);
device.Content(out var content);
content.Transfer(out var resources);
var property = new _tagpropertykey
{
fmtid = new Guid(0xE81E79BE, 0x34F0, 0x41BF, 0xB5, 0x3F, 0xF1, 0xA0, 0x6A, 0xE8, 0x78, 0x42),
pid = 0
};
uint optimalTransferSize = 0;
resources.GetStream(fileId, ref property, 0, ref optimalTransferSize, out IStream wpdStream);
var sourceStream = (System.Runtime.InteropServices.ComTypes.IStream)wpdStream;
using (var targetStream = new FileStream(Path.Combine(saveToPath, fileName), FileMode.Create, FileAccess.Write))
{
// Get the total size.
long written = 0;
long lPCt = 0;
unsafe
{
var buffer = new byte[1024];
int bytesRead;
do
{
sourceStream.Read(buffer, 1024, new IntPtr(&bytesRead));
targetStream.Write(buffer, 0, bytesRead);
written += 1024;
long PCt = length > 0 ? (100 * written) / length : 100;
if (PCt != lPCt)
{
lPCt = PCt;
Console.WriteLine("Progress: " + lPCt);
}
} while (bytesRead > 0);
}
}
}
finally
{
Disconnect(device);
}
}
}
If item has a parsing name like below, I was after the 5461 part from the final guid:
::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_22b8&pid_2e82#zy322kldjb#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{10001,,26401026048}\{00000009-0001-0001-0000-000000000000}\{00000075-0001-0001-0000-000000000000}\{00005461-0001-0001-0000-000000000000}
We can use the following code which will get the WPD_OBJECT_ID property from a ShellObject. More info on this and related properties here:
string GetFileId(ShellObject item)
{
const int WPD_OBJECT_ID = 2;
var property = item.Properties.GetProperty(new PropertyKey(new Guid("{ef6b490d-5cd8-437a-affc-da8b60ee4a3c}"), WPD_OBJECT_ID));
return property.ValueAsObject as string;
}
This returns the file id o5641, which can then be used in my TransferContentFromDevice method directly.
Thanks to #SimonMourier for pointing me in the right direction.

How to read serial port until timeout right after write to it?

I need to write and read data from serial port to my device. I've test certain approach where at first, I'm receiving the data using SerialDataReceivedEventArgs and I feel it is hard to read the port where I need to define the command that send where as the command is almost 200 commands.
My first approach is using:-
private void ObjCom_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
if (!ObjCom.IsOpen) return;
byte[] data = new byte[ObjCom.BytesToRead];
ObjCom.Read(data, 0, data.Length);
RaiseEventMsg("Buffer String: " + BitConverter.ToString(data).Replace("-", " "));
}
The RaiseEventMsg is a delegate event to pass current information to Main UI. The second approach is:-
private long lngTickCount = Convert.ToInt64(1000L);
public void StartWriteToPort()
{
byte[] Cmd = null;
string strCmd = string.Empty;
string strMsg = null;
bool bCont = true;
long lngCurrent = 0;
long lngNow = 0;
try
{
RaiseEventMsg("Start Write To Port");
ObjCom.DiscardOutBuffer();
ObjCom.DiscardInBuffer();
GetFullCommandByte(ref Cmd, Convert.ToByte(123)); // Referencing Cmd with return and pass Command List(various set of command)
ObjCom.Write(Cmd, 0, Cmd.Length);
strCmd = ByteArrayToString(Cmd); // Convert byte array to Hex string
RaiseEventMsg("Send: " + strCmd);
bool bTimeout = false;
lngCurrent = DateTime.Now.Ticks;
while (!bTimeout)
{
lngNow = DateTime.Now.Ticks;
if (lngNow > (lngCurrent + (3 * lngTickCount)))
{
bTimeout = true;
break;
}
}
lngCurrent = DateTime.Now.Ticks;
while (ObjCom.BytesToRead <= 0)
{
lngNow = DateTime.Now.Ticks;
if (lngNow > (lngCurrent + (1000 * lngTickCount)))
{
bCont = false;
break;
}
}
if (!bCont)
{
strMsg = "Error - Timeout Hit";
RaiseEventMsg(strMsg);
return;
}
int Idx = 0;
string strASCIIFull = string.Empty;
if ((ObjCom.BytesToRead > 0) & (bCont == true))
{
while (ObjCom.BytesToRead > 0)
{
var strASCII = ObjCom.ReadByte();
var TmpHex = System.Convert.ToString(strASCII, 16).ToUpper();
if (TmpHex.Length == 1)
{
strASCIIFull += (" 0" + TmpHex);
}
else
{
strASCIIFull += (" " + TmpHex);
}
lngCurrent = DateTime.Now.Ticks;
while (ObjCom.BytesToRead <= 0)
{
lngNow = DateTime.Now.Ticks;
if (lngNow > (lngCurrent + (2 * lngTickCount)))
{
bCont = false;
break;
}
}
Idx += 1;
}
}
RaiseEventMsg("Recv: " + strASCIIFull);
}
catch (System.Exception ex)
{
string error = $"Exception on StartWriteToPort. Message: {ex.Message}. StackTrace: {ex.StackTrace}";
}
}
Problem on second approach is when I call this function for second time, the timeout will hit . But for Serial event, it does not have the problem, the protocol for timeout is set to 1 seconds. My device currently connected using USB without converter. The input cable to device is type B port (like standard printer port).
Is the any other way to read directly from port or any improvement on current code?
You need to learn how to layer your code. At the moment you have one long function that tries to do everything.
If you had several smaller functions that did specific things like reading or writing a chunk of information then it would make what you are trying to do simpler.
For example, serial communications generally have some sort of protocol that encapsulates how the packets of information are stored. Say the protocol was "", then you know every packet starts with an STX byte (0x01), a length byte, which tells you how many bytes are in the section, and there must be an ETX byte (0x02) at the end. You could write a function that would return an array of bytes that are just the because the function would interpret the stream and extract the relevant parts.
Then it might be as simple as:
var packet1 = ReadPacket();
WritePacket(outputData);
var packet2 = ReadPacket();

I'm try to implement UPSP Label Generating

I am tryin to implement UPSP label generating but i am getting this error.
**API Authorization failure. DelivConfirmCertifyV3.0Request is not a valid API name for this protocol.**
if i test on browser, it's working fine
http://production.shippingapis.com/ShippingAPI.dll?API=Verify&XML=%3CAddressValidateRequest%20USERID=%22Testuserid%22%3E%3CAddress%20ID=%221%22%3E%3CAddress1%3E%3C/Address1%3E%3CAddress2%3E10051+Orr+%26amp%3b+Day+Rd%3C/Address2%3E%3CCity%3Esanta+fe+springs%3C/City%3E%3CState%3Eca%3C/State%3E%3CZip5%3E90670%3C/Zip5%3E%3CZip4%3E%3C/Zip4%3E%3C/Address%3E%3C/AddressValidateRequest%3E
Anyone know about this problem...
Code Is below:
public Package GetDeliveryConfirmationLabel(Package package)
{
string labeldate = package.ShipDate.ToShortDateString();
if (package.ShipDate.ToShortDateString() == DateTime.Now.ToShortDateString())
labeldate = "";
string url = "?API=DelivConfirmCertifyV3.0Request&XML=<DelivConfirmCertifyV3.0Request.0Request USERID=\"{0}\"><Option>{1}</Option><ImageParameters></ImageParameters><FromName>{2}</FromName><FromFirm>{3}</FromFirm><FromAddress1>{4}</FromAddress1><FromAddress2>{5}</FromAddress2><FromCity>{6}</FromCity><FromState>{7}</FromState><FromZip5>{8}</FromZip5><FromZip4>{9}</FromZip4><ToName>{10}</ToName><ToFirm>{11}</ToFirm><ToAddress1>{12}</ToAddress1><ToAddress2>{13}</ToAddress2><ToCity>{14}</ToCity><ToState>{15}</ToState><ToZip5>{16}</ToZip5><ToZip4>{17}</ToZip4><WeightInOunces>{18}</WeightInOunces><ServiceType>{19}</ServiceType><POZipCode>{20}</POZipCode><ImageType>{21}</ImageType><LabelDate>{22}</LabelDate><CustomerRefNo>{23}</CustomerRefNo><AddressServiceRequested>{24}</AddressServiceRequested><SenderName>{25}</SenderName><SenderEMail>{26}</SenderEMail><RecipientName>{27}</RecipientName><RecipientEMail>{28}</RecipientEMail></DelivConfirmCertifyV3.0Request.0Request>";
url = GetURL() + url;
//url = String.Format(url,this._userid, (int)package.LabelType, package.FromAddress.Contact, package.FromAddress.FirmName, package.FromAddress.Address1, package.FromAddress.Address2, package.FromAddress.City, package.FromAddress.State, package.FromAddress.Zip, package.FromAddress.ZipPlus4, package.ToAddress.Contact, package.ToAddress.FirmName, package.ToAddress.Address1, package.ToAddress.Address2, package.ToAddress.City, package.ToAddress.State, package.ToAddress.Zip, package.ToAddress.ZipPlus4, package.WeightInOunces.ToString(), package.ServiceType.ToString().Replace("_", " "), package.OriginZipcode, package.LabelImageType.ToString(), labeldate, package.ReferenceNumber, package.AddressServiceRequested.ToString(), package.FromAddress.Contact, package.FromAddress.ContactEmail, package.ToAddress.Contact, package.ToAddress.ContactEmail);
url = String.Format(url, this._userid, (int)package.LabelType, package.FromAddress.Contact, package.FromAddress.FirmName, package.FromAddress.Address1, package.FromAddress.Address2, package.FromAddress.City, package.FromAddress.State, package.FromAddress.Zip, package.FromAddress.ZipPlus4, package.ToAddress.Contact, package.ToAddress.FirmName, package.ToAddress.Address1, package.ToAddress.Address2, package.ToAddress.City, package.ToAddress.State, package.ToAddress.Zip, package.ToAddress.ZipPlus4, package.WeightInOunces.ToString(), package.ServiceType.ToString().Replace("_", " "), package.OriginZipcode, package.LabelImageType.ToString(), labeldate, package.ReferenceNumber, package.AddressServiceRequested.ToString(), "", "", "", "");
string xml = web.DownloadString(url);
if (xml.Contains("<Error>"))
{
int idx1 = xml.IndexOf("<Description>") + 13;
int idx2 = xml.IndexOf("</Description>");
int l = xml.Length;
string errDesc = xml.Substring(idx1, idx2 - idx1);
throw new USPSManagerException(errDesc);
}
int i1 = xml.IndexOf("<DeliveryConfirmationLabel>") + 27;
int i2 = xml.IndexOf("</DeliveryConfirmationLabel>");
package.ShippingLabel = StringToUTF8ByteArray(xml.Substring(i1, i2 - i1));
return package;
}
I get the error on
int i1 = xml.IndexOf("<DeliveryConfirmationLabel>") + 27;
The solution to your problem is the same on this stackoverflow question- How to remove 'SAMPLE DO NOT MAIL' from USPS shipping API image
And you can find the steps to get this done from my answer on that question or by directly following this link- https://stackoverflow.com/a/27936025/3748701
USPS returns the Label in Base64 string you'd be required to convert that into an image. In my application i was required to provide the image as downloadable file, so I have returned the file result from the controller-action. Below is the action which gets the Base64 string label from DB, converts it into image and provides as downloadable file-
public ActionResult GetReturnShippingLabel(int orderId, bool showFull)
{
string shippingLabel = new OrderRepository().GetOrderReturnShippingLabel(orderId);
if (!string.IsNullOrEmpty(shippingLabel))
{
byte[] bytes = Convert.FromBase64String(shippingLabel);
Image image = null;
MemoryStream ms = new MemoryStream(bytes, 0, bytes.Length);
ms.Write(bytes, 0, bytes.Length);
image = Image.FromStream(ms, true);
image.RotateFlip(RotateFlipType.Rotate90FlipNone);
if (!showFull)
image = image.GetThumbnailImage(326, 570, null, IntPtr.Zero);
ImageConverter converter = new ImageConverter();
byte[] imgArray = (byte[])converter.ConvertTo(image, typeof(byte[]));
return File(imgArray.ToArray(), "image/gif");
}
else
{
return null;
}
}

Encoding.ASCII.GetBytes issue with Matlab

The WriteWavHeader function implements a WAV header. The problem is that when I try to read the WAV file in Matlab with wavread, I fail. By adding a breakpoint in wavread, I've inspected that although Matlab reads the 'WAVE', 'fmt ', and 'data' headers fine (i.e., ck.ID is equal to 'WAVE', 'fmt ' and 'data' respectively in every iteration), it can't correctly read the 'end of file' string. Specifically, ck.ID is equal to a bunch of weird ASCII characters. When I hard code that ck.ID = 'end of file', I manage to get the wav file read. Any ideas on how to solve this issue?
static void WriteWavHeader(Stream stream, int dataLength)
{
using (var memStream = new MemoryStream(64))
{
int cbFormat = 18; //sizeof(WAVEFORMATEX)
WAVEFORMATEX format = new WAVEFORMATEX()
{
wFormatTag = 1,
nChannels = 1,
nSamplesPerSec = 16000,
nAvgBytesPerSec = 32000,
nBlockAlign = 2,
wBitsPerSample = 16,
cbSize = 0
};
using (var binarywriter = new BinaryWriter(memStream))
{
//RIFF header
WriteString(memStream, "RIFF");
binarywriter.Write(dataLength + 8 + cbFormat + 8 + 4); //File size - 8
WriteString(memStream, "WAVE");
WriteString(memStream, "fmt ");
binarywriter.Write(cbFormat);
//WAVEFORMATEX
binarywriter.Write(format.wFormatTag);
binarywriter.Write(format.nChannels);
binarywriter.Write(format.nSamplesPerSec);
binarywriter.Write(format.nAvgBytesPerSec);
binarywriter.Write(format.nBlockAlign);
binarywriter.Write(format.wBitsPerSample);
binarywriter.Write(format.cbSize);
//data header
WriteString(memStream, "data");
binarywriter.Write(dataLength);
memStream.WriteTo(stream);
WriteString(memStream, "end of file");
}
}
}
static void WriteString(Stream stream, string s)
{
byte[] bytes = Encoding.ASCII.GetBytes(s);
stream.Write(bytes, 0, bytes.Length);
}
Are you looking at this bit of code (edit wavread at about line 208)?
function [ck,msg] = read_ckinfo(fid)
msg = '';
ck.fid = fid;
ck.Data = [];
err_msg = getString(message('MATLAB:audiovideo:wavread:TruncatedChunkHeader'));
[s,cnt] = fread(fid,4,'char');
% Do not error-out if a few (<4) trailing chars are in file
% Just return quickly:
if (cnt~=4),
if feof(fid),
% End of the file (not an error)
ck.ID = 'end of file'; % unambiguous chunk ID (>4 chars)
ck.Size = 0;
else
msg = err_msg;
end
return
end
...
As far as I can tell there is no valid ID/chunk called "end of file" (it's also not four characters long). This function simply returns the 'end of file' string to the find_cktype function (see lines 76 and 99) as a flag. In other words you appear to be writing a string of data (your "weird ASCII characters") to your WAV file with:
WriteString(memStream, "end of file");
The way to check for the end of a file in Matlab is with feof or check the length of the output returned by fread.
If you want to read the WAV, I think that you'll write some actual WAV data that matches up with what your header says.

C# UnauthorizedAccessException error

I am transfering files through sockets. When I try to save files to a custom directory, I get this error using BinaryWrite function.
private void downloadFromServer()
{
try
{
byte[] buffer = new byte[5000 * 1024];
byte[] incomingFile = new byte[5000 * 1024];
buffer = Encoding.Default.GetBytes(getUserName.Text + "Download"
+ getFileName.Text + "end");
clientSocket.Send(buffer);
activityLog.AppendText("Preparing to download... \n");
while (incomingFile != null)
{
clientSocket.Receive(incomingFile);
int receivedBytesLen = incomingFile.Length;
int fileNameLen = BitConverter.ToInt32(incomingFile, 0);
File.WriteAllBytes(fileDir, incomingFile);
}
activityLog.AppendText("File saved to " + fileDir + "\n");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
File.WriteAllBytes(fileDir, incomingFile); requires file name. From variable name it looks like you are using folder name. I.e. should be #"e:\tempfile.bin" instead of #"e:\".
File.WriteAllBytes
Given a byte array and a file path, this method opens the specified file, writes the contents of the byte array to the file, and then closes the file.
Note if fileDir means file name than you should looks for other not-so-truthful names throughout your code...

Categories