I have a server-client socket chat application,
at the server folder I have a game folder where I have a javascript game that I wrote,pictures of the game, and an html page to run the game.
When the client writing the command "#game" the server will send him the game files, and the client will download the game files to a C directory.
I have tried to transfer the files in couple of ways all of them seem to fail, It's look like the html file and the JS files transfer completely but the pictures aren't complete and that's why the game isn't working...
I need to transfer the files using only sockets.
Server Side
I used the SendFile method and after every file data I sent "\d" for a sign to move to the next data so that client could know the different between files data.
public static bool Game(string msg, Socket socket)
{
if (msg.Equals("#game"))
{
ASCIIEncoding asc = new ASCIIEncoding();
string path = #"G:\הנדסת תוכנה\כיתה יא\ChatProject\ServerChat\game";
socket.Send(asc.GetBytes("#game"));
Byte[] preBuffer = asc.GetBytes("#download ");
Byte[] postBuffer = asc.GetBytes("#End");
socket.SendFile(path + #"\SpaceShip.js");
socket.Send(asc.GetBytes(#"\d"));
socket.SendFile(path + #"\page.html");
socket.Send(asc.GetBytes(#"\d"));
socket.SendFile(path + #"\Images\background.jpg");
socket.Send(asc.GetBytes(#"\d"));
socket.SendFile(path + #"\Images\defeat.png");
socket.Send(asc.GetBytes(#"\d"));
socket.SendFile(path + #"\Images\enemyspaceship.png");
socket.Send(asc.GetBytes(#"\d"));
socket.SendFile(path + #"\Images\friendlyspaceship.png");
socket.Send(asc.GetBytes(#"\d"));
socket.SendFile(path + #"\Images\IMG_06062017_225026_0.png");
socket.Send(asc.GetBytes(#"\d"));
socket.SendFile(path + #"\Images\laser.png");
socket.Send(asc.GetBytes(#"\d"));
socket.SendFile(path + #"\Images\victory.png");
socket.Send(asc.GetBytes(#"\d"));
Console.WriteLine("Game was send to "+socket.RemoteEndPoint);
return true;
}
return false;
}
Client Side
At the client side I first created the directory, and let myself to write the order of the files sending, at the Download function I moved every 2 char to check if I have the "\d" sign that I have sent, If I came across one I know it's the end of the data file and I write the data over the file I create.
public static void Game()
{
Console.WriteLine("downloading and opening the game...");
string path = #"C:\Game";
DirectoryInfo di = Directory.CreateDirectory(path);
di = Directory.CreateDirectory(path+#"\Images");
Console.WriteLine("The directory was created successfully ");
Console.WriteLine("reciving Data");
string[] pathArr = new string[]
{
path + #"\SpaceShip.js",
path + #"\page.html",
path + #"\Images\background.jpg",
path + #"\Images\defeat.png",
path + #"\Images\enemyspaceship.png",
path + #"\Images\friendlyspaceship.png",
path + #"\Images\IMG_06062017_225026_0.png",
path + #"\Images\laser.png",
path + #"\Images\victory.png"
};
Download(pathArr);
Console.WriteLine("Done!");
System.Diagnostics.Process.Start(path + #"\page.html");
}
public static void Download(string [] pathArr)
{
byte[] binDataIn = new byte[1025];
int k = socket.Receive(binDataIn, 0, 1025, SocketFlags.None);
ASCIIEncoding asc = new ASCIIEncoding();
string rcv = asc.GetString(binDataIn, 0, k);
string data = "";
int j = 0;
int i = 0;
while (j<=8)
{
string sign = rcv[i].ToString() + rcv[i + 1].ToString();
if (sign.Equals( #"\d"))
{
File.WriteAllText(pathArr[j], data);
data = "";
j++;
i += 2;
}
else
{
data += rcv[i];
i++;
}
if(rcv.Length-1<=i)
{
k = socket.Receive(binDataIn, 0, 1025, SocketFlags.None);
rcv = asc.GetString(binDataIn, 0, k);
i = 0;
}
}
}
I think I might complicated the process and there is a simpler way...
thanks to all the responding.
Related
I'm doing a c# wcf service in which I receive a bunch of images and the service merge them in a multiimage Tiff file. At the end of the service I want to delete the original files but I'm receiving an error that some other process is locking the file.
This is the code that receives the images (as a byte[] list) and write them to disk
public static List<string> SaveByteImagesToFile(List<byte[]> bytesToCopyIntoFiles, string imageReferenceType, string imageReferenceValue)
{
_applicationLogger.Debug(MethodBase.GetCurrentMethod().DeclaringType.Name, MethodBase.GetCurrentMethod().Name);
string imageFinalPath = string.Empty;
string joinImagesFilePath = string.Empty;
List<string> imagesFilePath = new List<string>();
int count = 1;
try
{
if (bytesToCopyIntoFiles.Count == 0)
{
throw new ArgumentNullException("bytesToCopyIntoFiles");
}
else
{
joinImagesFilePath = SettingsManager.GetServiceSetting(AppSettingsKeys.CopyImagesToFilePath, "NO_VALID_FILEPATH");
if (joinImagesFilePath.IsValidFilePath(out string errorMessage, true, true))
{
foreach (byte[] image in bytesToCopyIntoFiles)
{
var imageFileName = imageReferenceType + "_" + imageReferenceValue + "_" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + count.ToString();
imageFinalPath = joinImagesFilePath + Path.DirectorySeparatorChar + imageFileName + ".tiff";
using (FileStream stream = new FileStream(imageFinalPath, FileMode.Create, FileAccess.ReadWrite))
{
stream.Write(image, 0, image.Length);
stream.Flush();
}
imagesFilePath.Add(imageFinalPath);
count++;
}
}
else
{
exceptionMessageType = MainRepository.GetExceptionMessage("E171");
throw new IOException(exceptionMessageType.ExceptionMessage + " " + errorMessage);
}
}
return imagesFilePath;
}
catch
{
throw;
}
}
How or what can I use to prevent the service or any process to lock the file. As you can see I'm using the using scope for filestream without any luck.
Any ideas? Thanks
Resolved! By organizing the files in a certain order, when creating the multipage tiff, by the time the logic ends the worker already unlock the resources and I'm able now to delete them without any issue.
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();
I am having a problem receiving files from the client. Someone suggested that I should use binary serialization to send and receive messages in stream. Can you give me ideas on how I should serialize this? I just learned about serialization not long ago so I am quite confused on how I should associate it with my program.
This is the client that 'should' be serialize
public void sendthedata()
{
if (!_timer.Enabled) // If timer is not running send data and start refresh interval
{
SendData();
_timer.Enabled = true;
}
else // Stop timer to prevent further refreshing
{
_timer.Enabled = false;
}
}
private List<int> listedProcesses = new List<int>();
private void SendData()
{
String processID = "";
String processName = "";
String processPath = "";
String processFileName = "";
String processMachinename = "";
listBox1.BeginUpdate();
try
{
piis = GetAllProcessInfos();
for (int i = 0; i < piis.Count; i++)
{
try
{
if (!listedProcesses.Contains(piis[i].Id)) //placed this on a list to avoid redundancy
{
listedProcesses.Add(piis[i].Id);
processID = piis[i].Id.ToString();
processName = piis[i].Name.ToString();
processPath = piis[i].Path.ToString();
processFileName = piis[i].FileName.ToString();
processMachinename = piis[i].Machinename.ToString();
output.Text += "\n\nSENT DATA : \n\t" + processFileName + "\n\t" + processMachinename + "\n\t" + processID + "\n\t" + processName + "\n\t" + processPath + "\n";
}
}
catch (Exception ex)
{
wait.Abort();
output.Text += "Error..... " + ex.StackTrace;
}
NetworkStream ns = tcpclnt.GetStream();
String data = "";
data = "--++" + processFileName + " " + processMachinename + " " + processID + " " + processPath;
if (ns.CanWrite)
{
byte[] bf = new ASCIIEncoding().GetBytes(data);
ns.Write(bf, 0, bf.Length);
ns.Flush();
}
}
}
finally
{
listBox1.EndUpdate();
}
}
And deserializing in the server
private void recieveData()
{
NetworkStream nStream = tcpClient.GetStream();
ASCIIEncoding ascii = null;
while (!stopRecieving)
{
if (nStream.CanRead)
{
byte[] buffer = new byte[1024];
nStream.Read(buffer, 0, buffer.Length);
ascii = new ASCIIEncoding();
recvDt = ascii.GetString(buffer);
/*Received message checks if it has +##+ then the ip is disconnected*/
bool f = false;
f = recvDt.Contains("+##+");
if (f)
{
string d = "+##+";
recvDt = recvDt.TrimStart(d.ToCharArray());
clientDis();
stopRecieving = true;
}
//else if (recvDt.Contains("^^"))
//{
// new Transmit_File().transfer_file(file, ipselected);
//}
/* ++-- shutsdown/restrt/logoff/abort*/
else if (recvDt.Contains("++--"))
{
string d = "++--";
recvDt = recvDt.TrimStart(d.ToCharArray());
this.Invoke(new rcvData(addToOutput));
clientDis();
}
/*--++ Normal msg*/
else if (recvDt.Contains("--++"))
{
string d = "--++";
recvDt = recvDt.TrimStart(d.ToCharArray());
this.Invoke(new rcvData(addToOutput));
}
}
Thread.Sleep(1000);
}
}
public void addToOutput()
{
if (recvDt != null && recvDt != "")
{
output.Text += "\n Received Data : " + recvDt;
recvDt = null;
}
}
Thank you.
There are a couple of rules to follow when serialising a piece of data.
It's easy to convert data to bytes, but consider how to reconstruct the data on the other side. Assume that the server can't have any knowledge on what you sended.
In your serialiser you just convert a couple of strings into a byte[] and send it over. Example:
string x = "abcdef";
string y = "ghijk";
var bytes = Encoding.Ascii.GetBytes(x + y);
the server receives: "abcdefghijk";
Is it possible for the server to determine and reconstruct strings x and y?
Since the server has no knowledge of the length of either x and y: no.
There are ways to solve this:
Use fixed length fields. In my example x should always be 6 chars and y should always be 5 chars in length. decoding on the server then becomes as trivial as
string x = data.Substring(0, 6)
string y = data.Substring(6, 5)
Use delimiters between the fields. If you are familiar with cvs, the ',' splits the fields. This however has it drawbacks, how to handle a ',' somewhere in a string? The data send over would be like "abcdef,ghijk"
Send the size of each field before the content of the field.
A naive approach just to clarify: string x would be send as '6abcdef' and y as '5ghijk'
Doing all this things by hand can get really hairy and is something that I would consider only if really needed.
I would resort to existing frameworks that do an excellent job on this subject:
Json.net
protobuf ported by Jon skeet
In this case I would first create a class to define the data send to the server instead of a bunch of strings:
class ProcessInfo{
public string ProcessID {get;set;}
public string ProcessName {get;set;}
public string ProcessPath {get;set;}
public string ProcessFileName {get;set;}
public string ProcessMachinename {get;set;}
};
the using Json to serialise this:
var procinfo = new ProcessInfo{
ProcessId = "1",
...
};
var serialised = JsonConvert.SerializeObject(procinfo);
var bytes = Encoding.Utf8.GetBytes(serialised);
ns.Write(bytes, 0, bytes.Length);
And restore it on the server just by:
var procInfo = JsonConvert.DeserializeObject<ProcessInfo>(json);
I have never programmatically generated and sent email notifications before. What I need to do is this, if this program fails to move files or encounters an exception to generate an email and (preferably) attach a Log.txt file to the email then send it. This app will be ran from an enterprise scheduler and ran 1/hour to manage the files and folders.
Here is the functional code that I currently have (no email implementation exists yet) I have commented in the locations that I would like to send an email
using System;
using System.Configuration;
using System.IO;
using System.Net;
using System.Net.Mail;
using System.Runtime.InteropServices;
namespace FileOrganizer
{
class Program
{
//These are the folder to organize and delimeter that is in the filenames to split off a folder from
static string folder = ConfigurationManager.AppSettings["folder"]; //"C:\Users\MyUserName\Desktop\Organize Me"
static string delim = ConfigurationManager.AppSettings["delim"]; // delim = "__"
//location for the log.txt file
static string logPath = ConfigurationManager.AppSettings["logPath"]; //C:\Users\MyUserName\Desktop\Log.txt
//contact list from the app.config
static string emailTo = ConfigurationManager.AppSettings["notifyEmailAddress"]; //multiple email addresses delimited by a ; example = tom#domain.com;dick#differentDomain.com;harry#domain.com
//for the log.txt reporting
static int filesMoved = 0;
static int filesNOTmoved = 0;
static string fileNamesNOTmoved = "";
static int foldersCreated = 0;
static string message = "";
static string stackTrace = "";
//used for passing all the objects into the log method
static object[] details = new object[6];
static void Main(string[] args)
{
try
{
using (StreamWriter w = File.AppendText(logPath))
{
int total = organizeFolder(delim, folder);
details[0] = filesMoved;
details[1] = filesNOTmoved;
details[2] = fileNamesNOTmoved;
details[3] = foldersCreated;
details[4] = "No Errors Found";
details[5] = "No Errors Found";
Log(details, w);
if (filesNOTmoved > Convert.ToInt32(filesNOTmoved))
{
//generate email to notify of filesNames not moved (prefer to send Log.txt as attachment)
}
}
using (StreamReader r = File.OpenText(logPath))
{
DumpLog(r);
}
}
catch (Exception ex)
{
using (StreamWriter w = File.AppendText(logPath))
{
details[0] = filesMoved;
details[1] = filesNOTmoved;
details[2] = fileNamesNOTmoved;
details[3] = foldersCreated;
details[4] = ex.Message.ToString();
details[5] = ex.StackTrace.ToString();
Log(details, w);
}
//generate email to notify of Error and (prefer to send Log.txt as attachment)
using (StreamReader r = File.OpenText(logPath))
{
DumpLog(r);
}
}
}
/*Takes a folder and organizes it into folder by naming folder whatever
* is in front of the delimeter Example -->(folderName__fileName.txt would be moved
* to a new or existing folder named folderName. Final path for file would
* look like this folderName\folderName__fileName.txt)
*
* It will not move file if it already exists in the new location, instead
* it prompts user that they should rename file and run program again.*/
static int organizeFolder(string delimeter, string rootPath)
{
//counter for total files in Folder
int Count = 0;
int totalMoved = 0;
FileInfo[] fileNames;
DirectoryInfo di = new DirectoryInfo(rootPath);
//set all file names as a string from network directory into an array
fileNames = di.GetFiles("*.*");
Count = fileNames.Length;
//Count = 0;//just to test exception handling
//if no files exist in network folder throw error message.
if (Count == 0)
{
fileNamesNOTmoved = "No Files Were In Directory to Move.";
}
else //files exist in network folder
{
int delimIndex = 0;
string folderName;
for (int i = 0; i < Count; i++)
{
if (fileNames[i].ToString().Contains(delimeter))
{
delimIndex = fileNames[i].ToString().IndexOf(delimeter);
folderName = fileNames[i].ToString().Substring(0, delimIndex);
//if folder doesnt exist create it here.
folderCreation(rootPath, folderName);
if (!File.Exists(rootPath + #"\" + folderName + #"\" + fileNames[i].Name))
{
File.Move(rootPath + #"\" + fileNames[i].ToString(), rootPath + #"\" + folderName + #"\" + fileNames[i].Name);
filesMoved++;
}
else
{
if (fileNamesNOTmoved == "")
fileNamesNOTmoved += "| ";
fileNamesNOTmoved += fileNames[i].Name + " | ";
filesNOTmoved++;
}
totalMoved++;
}
}
}
return totalMoved;
}
//if folder does not exist this method will create it
private static void folderCreation(string strTempPath, string folderName)
{
strTempPath = strTempPath + #"\" + folderName;
if (!Directory.Exists(strTempPath))
{
//Create \folderName
Directory.CreateDirectory(strTempPath);
foldersCreated++;
}
}
//adds entries to the log.txt file
public static void Log(object[] details, TextWriter w)
{
w.Write("\r\nLog Entry : ");
w.WriteLine("{0} {1}", DateTime.Now.ToShortTimeString(), DateTime.Now.ToShortDateString());
w.WriteLine(" :");
w.WriteLine(" :{0}", "Files Moved = " + details[0].ToString());
w.WriteLine(" :{0}", "Folders Created = " + details[3].ToString());
w.WriteLine(" :{0}", "Files Not Moved = " + details[1].ToString());
w.WriteLine(" :{0}", "Files Names Not Moved = {" + details[2].ToString() + "}");
w.WriteLine(" :{0}", "Error Message = " + details[4].ToString());
w.WriteLine(" :{0}", "Error Stack Trace = " + details[5].ToString());
w.WriteLine("---------------------------------------------------------------------------------------");
}
public static void DumpLog(StreamReader r)
{
string line;
while ((line = r.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
}
}
Basically would like the email to say:
Subject: Data Management Error Notification
Body: This is an Auto-Generated email to notify you there
was an error attempting to clean up the Files in the Directory.
Please refer to Attached Log.txt File for more detailed information.
Attachment: Log.txt
As it turns out SMTP was the way to go and Due to restrictions on my local machine I could only access it from the Dev, Qua, & Prd Servers. Once tested as admin from any of those locations.. email sent perfectly!!!
using the App.Config to hold all my To's, Froms, and the SMTP Host info and passing HTML as a string object into the method, here is the method I used to send email.
public static void sendMail(string msg)
{
SmtpClient smtpClient = new SmtpClient();
MailMessage message = new MailMessage();
MailAddress fromAddress = new MailAddress(emailFrom);
smtpClient.Host = smtpHost;
message.From = fromAddress;
message.Subject = "Test Email";
message.IsBodyHtml = true;
message.Body = msg;
message.To.Add(emailTo);
message.Priority = MailPriority.High;
smtpClient.Send(message);
}
I want to ask how to open a specific file (the file is out of the server, i have a relative path to it stored in config file) with its application, when clicking on a specific link button or hyper link...
like :
opening
.docx with word.
or
.pdf with acrobat reader
i tried several methods but , i get different errors like
Cannot use a leading .. to exit above the top directory
my .cs:
public void ProcessRequest(HttpContext context)
{
int newsId = int.Parse(context.Session["newsId"].ToString());
int FK_UnitId = int.Parse(context.Session["UserData"].ToString());
string dirPathForTextFiles = ConfigurationManager.AppSettings.GetValues("ThePath").First() + "/" + "NewsTextFiles" + "/" + "UnitNum" + FK_UnitId.ToString() + "_" + "NewsNum" + newsId + "/";
DataTable UpdatedDateTable = (DataTable)context.Session["theLastUpdatedTextFile"];
UpdatedDateTable.AcceptChanges();
context.Session.Add("currentTextFile", UpdatedDateTable);
List<string> l = new List<string>(UpdatedDateTable.Rows.Count);
try
{
l.Add(dirPathForTextFiles + UpdatedDateTable.Rows[0]["fileName"].ToString());
context.Response.ContentType = getContentType(dirPathForTextFiles + UpdatedDateTable.Rows[0]["fileName"].ToString());
System.Diagnostics.Process.Start(l[0]);
context.ClearError();
}
catch (IOException e)
{
string message = e.Message;
}
}
string getContentType(String path)
{
switch (Path.GetExtension(path))
{
case ".doc": return " application/msword";
case ".docx": return "application/msword";
case ".pdf": return "application/pdf";
default: break;
}
return "";
}
In order to get the full file path on the server you'll want to use Server.MapPath.
string fullFileName = Server.MapPath("../myFile.pdf");
Edit: After that you'll need the Process object to "run" it:
System.Diagnostics.Process.Start(fullFileName);
Edit 2: If you want the file to be opened on the client side, your best bet is to create and HTTP Handler and set the appropriate mime type on your response before streaming it out from your handler.
Edit 3: Code to stream a file out to client.
public void ProcessRequest(HttpContext context)
{
int newsId = int.Parse(context.Session["newsId"].ToString());
int FK_UnitId = int.Parse(context.Session["UserData"].ToString());
string dirPathForTextFiles = ConfigurationManager.AppSettings.GetValues("ThePath").First() + "/" + "NewsTextFiles" + "/" + "UnitNum" + FK_UnitId.ToString() + "_" + "NewsNum" + newsId + "/";
DataTable UpdatedDateTable = (DataTable)context.Session["theLastUpdatedTextFile"];
UpdatedDateTable.AcceptChanges();
context.Session.Add("currentTextFile", UpdatedDateTable);
List<string> l = new List<string>(UpdatedDateTable.Rows.Count);
try
{
l.Add(dirPathForTextFiles + UpdatedDateTable.Rows[0]["fileName"].ToString());
context.Response.ContentType = getContentType(dirPathForTextFiles + UpdatedDateTable.Rows[0]["fileName"].ToString());
using (FileStream fs = new FileStream(l[0], FileMode.Open, FileAccess.Read))
{
long chunkSize = fs.Length;
byte[] buf = new byte[chunkSize];
int bytesRead = 1;
bytesRead = fs.Read(buf, 0,(int)chunkSize);
if (bytesRead > 0) context.Response.OutputStream.Write(buf, 0, buf.Length);
context.Response.OutputStream.Flush();
}
}
catch (IOException e)
{
string message = e.Message;
}
}
System.Diagnostics.Process.Start("Start FilePath")