I'm working on client-server multithreading application:
Progress of communication is:
Server listens on socket
Client connects and send request or requests to server
Each request is ended by 0x04
Server must proceess each request with operation which is slower than incoming requests
I have a problem in "ProcessClient" method when two requests occur in short time and first request cannot be processed till the end of method beacuse second request is coming to process. Problem occurs after foreach loop:
foreach (var t in invoices)
{
SaveToDataBase(t);
}
Method does not executes till the end and it does not sends response to client with following code snippet:
var ResponseFile = ResponseClientFolder + "\\" + ResponseClientFileName + x + ".txt";
StreamWriter sw = File.CreateText(ResponseFile);
sw.WriteLine(_odgovor);
sw.Close();
_odgovor = string.Empty;
SendToClient(ResponseFile);
beacuse second request occurs at "ProcessClient" method.
Is there any way to solve this problem. I was looking for many solution without success.
Whole code is below:
private void RunListener()
{
try
{
_listener = new TcpListener(IPAddress.Parse(ServerAddres), ServerPort);
_listener.Start();
while (true)
{
TcpClient client = _listener.AcceptTcpClient();
Invoke(new Action(() => { }));
ThreadPool.QueueUserWorkItem(ProcessClient, client);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, #"Run listener");
}
}
private void ProcessClient(object state)
{
try
{
byte[] bytes = new byte[1024];
TcpClient client = state as TcpClient;
StringBuilder completeMessage = new StringBuilder();
if (client == null) return;
networkStream = client.GetStream();
int bytesRead = 0;
do
{
bytesRead = networkStream.Read(bytes, 0, bytes.Length);
completeMessage.AppendFormat("{0}", Encoding.Default.GetString(bytes, 0, bytesRead));
} while (bytesRead > 0 && bytes[bytesRead - 1] != 0x04);
completeMessage = completeMessage.Replace(#"”", "");
string datetime = DateTime.Now.ToString();
var x = datetime.Replace(".", string.Empty).Replace(":", string.Empty).Replace(" ", string.Empty);
var inputfilename = "Racun" + x + ".txt";
StreamWriter sws = File.CreateText(inputfilename);
sws.WriteLine(completeMessage);
sws.Close();
string data = completeMessage.ToString();
char[] delimiters = { '\r', '\n' };
string[] invoices = data.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
foreach (var t in invoices)
{
SaveToDataBase(t);
}
var ResponseFile = ResponseClientFolder + "\\" + ResponseClientFileName + x + ".txt";
StreamWriter sw = File.CreateText(ResponseFile);
sw.WriteLine(_odgovor);
sw.Close();
_odgovor = string.Empty;
SendToClient(ResponseFile);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, #"Proces client");
}
}
private void SendToClient(string ResponseFile)
{
try
{
byte[] byteData = File.ReadAllBytes(ResponseFile);
List<byte> byteDat = new List<byte>();
byteDat.AddRange(byteData);
byteDat.Add(0x04);
byteData = byteDat.ToArray();
networkStream.Write(byteData, 0, byteData.Length);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, #"Send to client");
}
}
Related
So i am trying to write a simple proxy/relay to download a webpage trough. But it does not work very well. Sometimes the webpage is empty, or the images on the webpage are corrupted and incomplete, etc. So, it must be a networking problem. (the network stream is not completely read).
How can i solve this issue?
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace TrafficRerouter
{
class Program
{
private static int bufferSize = 8196;
private static string destIp = "www.projectrho.com";
static void Main(string[] args)
{
StartTcpListener(80);
}
private static byte[] SendReceiveRemoteServer(string host, int port, byte[] data)
{
try
{
// Create a TcpClient.
// Note, for this client to work you need to have a TcpServer
// connected to the same address as specified by the server, port
// combination.
var client = new TcpClient(host, port);
// Get a client stream for reading and writing.
// Stream stream = client.GetStream();
var stream = client.GetStream();
// Send the message to the connected TcpServer.
stream.Write(data, 0, data.Length);
var str = Encoding.Unicode.GetString(data);
Console.Write("\nSent to server: ");
Col_Out(RemoveBinaryData(str), ConsoleColor.Red);
// Receive the TcpServer.response.
// Read the first batch of the TcpServer response bytes.
var bytes = new byte[bufferSize];
var allBytes = new List<byte>();
var i = stream.Read(bytes, 0, bytes.Length);
// Loop to receive all the data sent by the client.
while (i != 0)
{
allBytes.AddRange(bytes);
bytes = new Byte[bufferSize];
i = stream.DataAvailable ? stream.Read(bytes, 0, bytes.Length) : 0;
}
str = Encoding.Unicode.GetString(data);
Console.WriteLine("\nReceived from server: ");
Col_Out(RemoveBinaryData(str), ConsoleColor.DarkRed);
// Close everything.
stream.Close();
client.Close();
return allBytes.ToArray();
}
catch (ArgumentNullException e)
{
Console.WriteLine("ArgumentNullException: {0}", e);
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
Console.WriteLine("\n Press Enter to continue...");
return new byte[0];
}
private static void StartTcpListener(int port)
{
TcpListener server = null;
try
{
server = new TcpListener(IPAddress.Loopback, port);
// Start listening for client requests.
server.Start();
// Enter the listening loop.
while (true)
{
string s_received = "";
Console.WriteLine("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
var client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
// Get a stream object for reading and writing
var stream = client.GetStream();
// Buffer for reading data
var bytes = new Byte[bufferSize];
var allBytes = new List<byte>();
var i = stream.Read(bytes, 0, bytes.Length);
// Loop to receive all the data sent by the client.
while (i != 0)
{
allBytes.AddRange(bytes);
bytes = new Byte[bufferSize];
i = stream.DataAvailable ? stream.Read(bytes, 0, bytes.Length) : 0;
}
if (allBytes.Count > 0)
{
Console.Write("\nReceived from client : ");
Col_Out(RemoveBinaryData(Encoding.UTF8.GetString(allBytes.ToArray())) + '\n', ConsoleColor.DarkGreen);
var received = SendReceiveRemoteServer(destIp, 80, allBytes.ToArray());
s_received = Encoding.Unicode.GetString(received);
// Send back a response.
stream.Write(received, 0, received.Length);
Console.Write("\nSent to client : ");
Col_Out(RemoveBinaryData(s_received) + '\n', ConsoleColor.Green);
}
// Shutdown and end connection
client.Close();
}
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
Console.WriteLine("\nHit enter to continue...");
}
private static char[] good_chars = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz/.,;:[]=+-_1234567890()*&\n\r".ToArray();
static string RemoveBinaryData(string s)
{
StringBuilder r = new StringBuilder();
foreach (var c in s)
{
if (good_chars.Contains(c)) r.Append(c);
}
return (r.ToString() + "\n[BINARY_DATA]").Replace("\n", "█ ") + "\n";
}
static void Col_Out(string str, ConsoleColor c)
{
var oldc = Console.ForegroundColor;
Console.ForegroundColor = c;
Console.Write(str);
Console.ForegroundColor = oldc;
}
}
}
I want to make a simple client-server application. The server waits for connection from clients. The client can send various queries (short strings of less than 100 char) to the server and the server should respond to these queries by sending strings or files.
I found code online that uses a tcpListener.AcceptSocket() and I can send and receive strings from server and code that uses tcpListener.AcceptTcpClient() and I can send files to a different server program.
Below there is a function for sending files via TcpIP and one for sending strings via TcpIP. How should the server code look like, to acommodate both functions? The server is a console program.
public void SendFileViaTCP(string sFile, string sIPAddress, int portNo)
{
byte[] sendingBuffer = null;
TcpClient client = null;
toolStripStatusLabel1.Text = "";
lbConnect.Items.Clear();
progressBar1.Value = 0;
Application.DoEvents();
NetworkStream networkStream = null;
int bufferSize = 5000;
string checksum = CalculateMD5(sFile);
lbConnect.Items.Add("File " + sFile + " checksum = " + checksum);
try
{
client = new TcpClient(sIPAddress, portNo);
toolStripStatusLabel1.Text = "Connected to the Server...\n";
networkStream = client.GetStream();
FileStream fileStream = new FileStream(sFile, FileMode.Open, FileAccess.Read);
long fsLength = fileStream.Length;
int nPackets = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(fsLength) / Convert.ToDouble(bufferSize)));
progressBar1.Maximum = nPackets;
Application.DoEvents();
int currentPacketLength;
for (int i = 0; i < nPackets; i++) {
if (fsLength > bufferSize) {
currentPacketLength = bufferSize;
fsLength -= currentPacketLength;
Application.DoEvents();
}
else {
currentPacketLength = Convert.ToInt32(fsLength);
}
sendingBuffer = new byte[currentPacketLength];
fileStream.Read(sendingBuffer, 0, currentPacketLength);
networkStream.Write(sendingBuffer, 0, (int)sendingBuffer.Length);
progressBar1.PerformStep();
Application.DoEvents();
}
toolStripStatusLabel1.Text = "Sent " + fileStream.Length.ToString() + " bytes to the server";
fileStream.Close();
}
catch (Exception ex) {
Console.WriteLine(ex.Message);
}
finally {
networkStream.Close();
client.Close();
}
}
void SendString(string str, string sIPAddress, int portNo)
{
try {
TcpClient tcpClient = new TcpClient();
lbConnect.Items.Add("Connecting...");
Application.DoEvents();
// use the ipaddress as in the server program
var tsk = tcpClient.ConnectAsync(sIPAddress, portNo);
tsk.Wait(3000); // here we set how long we want to wait before deciding the server is not responding.
lbConnect.Items.Add("Connected");
lbConnect.Items.Add("Sending string: " + str);
Application.DoEvents();
Stream stream = tcpClient.GetStream();
ASCIIEncoding asen= new ASCIIEncoding();
byte[] ba=asen.GetBytes(str);
lbConnect.Items.Add("Transmitting...");
Application.DoEvents();
stream.Write(ba,0,ba.Length);
byte[] bb=new byte[100];
int k = stream.Read(bb,0,100);
string sResponse = string.Empty;
for (int i = 0; i < k; i++) {
sResponse += Convert.ToChar(bb[i]);
}
lbConnect.Items.Add(sResponse);
Application.DoEvents();
tcpClient.Close();
}
catch (Exception e) {
lbConnect.Items.Add("Error: " + e.StackTrace);
Application.DoEvents();
}
}
I'm making a server - client program using TcpClient and server.
To send from the server I use:
static void send(string data)
{
sw.WriteLine(data + Environment.NewLine);
}
And when the client connects I'm sending some text:
client = listener.AcceptTcpClient();
sr = new StreamReader(client.GetStream());
sw = new StreamWriter(client.GetStream());
string line;
try
{
send("Hello world");
} //More code
And to read from client:
string data;
data = sr.ReadLine();
if(data != string.Empty || data != null)
{
MessageBox.Show(data);
}
I tried putting inside while(true) and it froze, I tried putting inside a timer tick loop and it froze...
How do I fix this?
P.S: The client and the server are 2 different projects.
I believe you need something like this:
try
{
listen = new TcpListener(myAddress, port);
listen.Start();
Byte[] bytes;
while (true)
{
TcpClient client = listen.AcceptTcpClient();
NetworkStream ns = client.GetStream();
if(client.ReceiveBufferSize > 0){
bytes = new byte[client.ReceiveBufferSize];
ns.Read(bytes, 0, client.ReceiveBufferSize);
string msg = Encoding.ASCII.GetString(bytes); //the message incoming
MessageBox.Show(msg);
}
}
}
catch(Exception e)
{
//e
}
Then have this code as a background thread:
Thread thread = new Thread(the functions name);
thread.IsBackground = true;
thread.Start();
I hope I understand what you need.
Try this one, grandpa's way.
int i = 0;
while (stream.DataAvailable == true)
{
bytes[i] = ((byte)stream.ReadByte());
i++;
}
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
I keep getting the following exception when a client connects to the TCPListener.
Exception:
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.NetworkStream'.
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at Test.Server.ProcessClient(Object client, Object clientId)
Server.cs
public class Server
{
private TcpListener tcpListener;
private Thread listenThread;
public event EventHandler<EventLogArgs> EventLog;
public Server()
{
// Startup Code
ThreadPool.SetMinThreads(50, 50);
}
void UpdateEventLog(EventLogArgs e)
{
if (EventLog != null)
{
EventLog(this, e);
}
}
public void Start(string ip, int port_num)
{
Globals.listen = true;
Int32 port = port_num;
IPAddress address = IPAddress.Parse(ip);
this.tcpListener = new TcpListener(address, port);
Socket listenerSocket = this.tcpListener.Server;
LingerOption lingerOption = new LingerOption(true, 10);
listenerSocket.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.Linger,
lingerOption);
this.listenThread = new Thread(ListenForClients);
this.listenThread.Start();
UpdateEventLog(new EventLogArgs("Started server..."));
}
public void Stop()
{
Globals.listen = false;
UpdateEventLog(new EventLogArgs("Stop server request sent..."));
}
private void ListenForClients()
{
this.tcpListener.Start();
while (Globals.listen)
{
if (!this.tcpListener.Pending())
{
// This is so we can stop the server.
Thread.Sleep(25); // choose a number (in milliseconds) that makes sense
continue; // skip to next iteration of loop
}
//blocks until a client has connected to the server
TcpClient client = this.tcpListener.AcceptTcpClient();
Globals.clientRequests++;
int clientRequest = Globals.clientRequests;
UpdateEventLog(new EventLogArgs("(" + Globals.clientRequests + ") Client connected...\r\n"));
ThreadPool.QueueUserWorkItem(o => ProcessClient(client, clientRequest));
}
UpdateEventLog(new EventLogArgs("Stopped server!"));
this.tcpListener.Stop();
}
private void ProcessClient(object client, object clientId)
{
TcpClient tcpClient = (TcpClient)client;
int clientRequestId = (int)clientId;
NetworkStream clientStream = tcpClient.GetStream();
byte[] clientRequestRaw = new byte[1024];
int bytesRead;
UpdateEventLog(new EventLogArgs("(" + clientRequestId + ") Process client request..."));
while (true)
{
bytesRead = 0;
try
{
//blocks until a client sends a message
bytesRead = clientStream.Read(clientRequestRaw, 0, 512);
}
catch
{
//a socket error has occured
UpdateEventLog(new EventLogArgs("(" + clientRequestId + ") SOCKET ERROR\r\n\r\n" + e));
break;
}
if (bytesRead == 0)
{
//the client has disconnected from the server
UpdateEventLog(new EventLogArgs("(" + clientRequestId + ") Client disconnected from server, nothing sent."));
break;
}
//message has successfully been received.
ASCIIEncoding encoder = new ASCIIEncoding();
string clientRequest = encoder.GetString(clientRequestRaw, 0, bytesRead);
string[] cmd;
string success;
Dictionary<string, string> headers = new Dictionary<string, string>();
Dictionary<string, string> contents = new Dictionary<string, string>();
if (clientRequest.Length == 0)
{
return;
}
// Parse HTTP request
Parse Parse = new Parse();
Parse.HTTPRequest(clientRequest, out success, out cmd, out headers, out contents);
string response;
if (success == "TRUE")
{
response = "HTTP/1.1 200 OK\r\n\r\nHello World!\r\n";
}
else
{
response = "HTTP/1.1 200 OK\r\n\r\nHello Error!\r\n";
}
ResponseToClient(client, response);
clientStream.Close();
UpdateEventLog(new EventLogArgs("(" + clientRequestId + ") Server response...\r\n\r\n" + response));
}
tcpClient.Close();
UpdateEventLog(new EventLogArgs("(" + clientRequestId + ") Client disconnected."));
}
private void ResponseToClient(object client, string response)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes(response);
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}
}
The Server class is started from the main thread like so:
this.server = new Server();
this.server.EventLog += new EventHandler<EventLogArgs>(UpdateEventLog);
ThreadPool.QueueUserWorkItem(o => this.server.Start("127.0.0.1", 3000));
What am I doing wrong here?
I have taken the while loop out from the ProcessClient() method and this seems to have fixed the problem. Thanks anyway.
private void ProcessClient(object client, object clientId)
{
TcpClient tcpClient = (TcpClient)client;
int clientRequestId = (int)clientId;
NetworkStream clientStream = tcpClient.GetStream();
byte[] clientRequestRaw = new byte[1024];
int bytesRead;
UpdateEventLog(new EventLogArgs("(" + clientRequestId + ") Process client request..."));
while (true)
{
bytesRead = 0;
try
{
//blocks until a client sends a message
bytesRead = clientStream.Read(clientRequestRaw, 0, 512);
}
catch (Exception e)
{
//a socket error has occured
UpdateEventLog(new EventLogArgs("(" + clientRequestId + ") SOCKET ERROR\r\n\r\n" + e));
break;
}
if (bytesRead == 0)
{
//the client has disconnected from the server
UpdateEventLog(new EventLogArgs("(" + clientRequestId + ") Client disconnected from server, nothing sent."));
break;
}
//message has successfully been received.
ASCIIEncoding encoder = new ASCIIEncoding();
string clientRequest = encoder.GetString(clientRequestRaw, 0, bytesRead);
string[] cmd;
string success;
Dictionary<string, string> headers = new Dictionary<string, string>();
Dictionary<string, string> contents = new Dictionary<string, string>();
if (clientRequest.Length == 0)
{
return;
}
// Parse HTTP request
Parse Parse = new Parse();
Parse.HTTPRequest(clientRequest, out success, out cmd, out headers, out contents);
string response;
if (success == "TRUE")
{
response = "HTTP/1.1 200 OK\r\n\r\nHello World!\r\n";
}
else
{
response = "HTTP/1.1 200 OK\r\n\r\nHello Error!\r\n";
}
ResponseToClient(client, response);
clientStream.Close();
UpdateEventLog(new EventLogArgs("(" + clientRequestId + ") Server response...\r\n\r\n" + response));
}
tcpClient.Close();
UpdateEventLog(new EventLogArgs("(" + clientRequestId + ") Client disconnected."));
}
You have to give the network right service.
Write services.msc in run,then find your service.
YourService->Properties-> Log On-> Log On as Network
Since you solved your problem I'm just gonna give you two hints:
First of all, do not use the thread pool to make synchronous operations asynchronous. It's a waste of resources. Use the asynchronous methods instead (BeginAccept/EndAccept etc).
Next break your class into multiple classes. One taking care of the server parts only and one taking care of the client parts only. It makes your code a lot easier to follow (even for you :)).
Anyway don't use if (success == "TRUE")!
I'm trying to retrieve a list of files from an FTP server, but I'm getting some weird non-ASCII responses.
Here is the code that I am using:
public string[] getFileList(string mask)
{
if(!logined)
{
login();
}
Socket cSocket = createDataSocket();
this.getSslDataStream(cSocket);
sendCommand("PASV");
sendCommand("LIST " + "*"+mask);
stream2.AuthenticateAsClient(remoteHost,
null,
System.Security.Authentication.SslProtocols.Ssl3 |
System.Security.Authentication.SslProtocols.Tls,
true);
if(!(retValue == 150 || retValue == 125))
{
throw new IOException(reply.Substring(4));
}
StringBuilder mes = new StringBuilder();
while(true)
{
int bytes = cSocket.Receive(buffer, buffer.Length, 0);
mes.Append(ASCII.GetString(buffer, 0, bytes));
if(bytes < buffer.Length)
{
break;
}
}
string[] seperator = {"\r\n"};
string[] mess = mes.ToString().Split(seperator, StringSplitOptions.RemoveEmptyEntries);
cSocket.Close();
readReply();
if(retValue != 226)
{
throw new IOException(reply.Substring(4));
}
return mess;
}
The response I get from the FTP server is this:
WRITE:PASV
READ:227 Entering Passive Mode (10,0,2,24,5,119)`
WRITE:LIST *.dat
READ:150 Opening ASCII mode data connection for /bin/ls.
READ:226 Transfer complete.
It stops there. The string array that it returns contains one index with some non-ascii characters. Looks like a bunch of garbage. Perhaps my ASCII.GetString part is wrong? I'm not quite sure.
Thanks in advance.
I wrote a pretty easy to use wrapper library for all the FtpWebRequest stuff. If you care to check it out, it's here https://gist.github.com/1242616
I use it in a lot of production environments and it hasn't failed me yet.
For what it's worth, the System.Net namespace has the FtpWebRequest and FtpWebResponse classes beginning in .Net 2.0.
Here's some code I've used that writes the server's files to a local file:
...
FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create(address);
ftpRequest.Credentials = new NetworkCredential(username, password);
ftpRequest.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
ftpRequest.KeepAlive = false;
FtpWebResponse ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
sr = new StreamReader(ftpResponse.GetResponseStream());
sw = new StreamWriter(new FileStream(fileName, FileMode.Create));
sw.WriteLine(sr.ReadToEnd());
sw.Close();
ftpResponse.Close();
sr.Close();
...
public Socket BuildDataConn(Socket FirstSocket)
{
string ret = "";
string RemoteIP = "";
int RemotePort = 0;
SendCommand("PASV");
int id = 0;
id = strMsg.LastIndexOf(')');
if (id != 0)
{
string tmp = strMsg.Substring(strMsg.LastIndexOf('(') + 1, id - strMsg.LastIndexOf('(') - 1);
string[] bByte = tmp.Split(',');
RemotePort = int.Parse(bByte[4]) * 256 + Byte.Parse(bByte[5]);
RemoteIP = bByte[0]+"." + bByte[1] + "." + bByte[2] + "." + bByte[3];
}
Socket NewConn = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint RemoteIPPort = new IPEndPoint(IPAddress.Parse(RemoteIP), RemotePort);
try
{
NewConn.Connect(RemoteIPPort);
}
catch
{
throw new IOException("unable to Connect !");
}
return NewConn;
}
Instead of using cSocket to receive response data,you need to get a second socket and then use the socket to receive response data. the second socket will response for sending back information. And make sure you had change your FTP working directory before you sendcommand LIST.
public List<string> GetFileNames()
{
if (!bConnected)
{
Open();
}
List<string> retObj = new List<string>();
Socket dataSock = BuildDataConn(mySocket);
SendCommand("NLST");
string dataSockMsg = "";
buffer = new byte[BLOCK_SIZE];
while (true)
{
int iBytes = dataSock.Receive(buffer, buffer.Length, 0);
dataSockMsg += System.Text.Encoding.ASCII.GetString(buffer, 0, iBytes);
if (iBytes < buffer.Length)
{
break;
}
}
string[] message = dataSockMsg.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
dataSock.Close();
foreach (string obj in message)
{
retObj.Add(obj);
}
return retObj;
}