I've written my own HTTP server to embed in a desktop application and it works (spins up a server on localhost), except that I'm getting a strange request on the socket that is causing the connection to be closed so that no new requests are being handled. The request is occuring about 15 seconds after I open the web page. The packet contains a long series of \0\0\0\0\0\0\0\0\0\0\0\0...... when I examine it. I have no idea what's causing this or how to handle it. For those first 15 seconds, I'm able to do everything I need to do, but once this happens, no new requests can be made and the server won't respond to any new requests. It also doesn't happen every time I launch the application but I can't pin down why.
while (true)
{
//Accept a new connection
Socket mySocket = _listener.AcceptSocket();
if (mySocket.Connected)
{
Byte[] bReceive = new Byte[1024];
int i = mySocket.Receive(bReceive, bReceive.Length, 0);
string sBuffer = Encoding.ASCII.GetString(bReceive);
if (sBuffer.Substring(0, 3) != "GET")
{
Console.WriteLine(sBuffer);
mySocket.Close();
return;
}
........handle valid requests
}
}
Try something like this:
while (true)
{
//Accept a new connection
Socket mySocket = _listener.AcceptSocket();
if (mySocket.Connected)
{
Byte[] bReceive = new Byte[1024];
int i = mySocket.Receive(bReceive, bReceive.Length, 0);
if(i > 0) // added check to make sure data is received
{
string sBuffer = Encoding.ASCII.GetString(bReceive, 0, i); // added index and count
if (sBuffer.Substring(0, 3) != "GET")
{
Console.WriteLine(sBuffer);
mySocket.Close();
return;
}
........handle valid requests
}
}
}
Ultimately - you will need to do something if i == 1024 - because if it does, there is more data than you are reading in mySocket.Receive.
As a side note - I might change
if (sBuffer.Substring(0, 3) != "GET")
to
if (sBuffer.StartsWith("GET"))
It's slightly easier to read - and has the added benefit of not requiring a change to the substring length if (for some odd reason) GET changed to something else.
Edit - this will allow for multiple calls to mySocket.Receive when more data than 1024 bytes is encountered:
while (true)
{
//Accept a new connection
Socket mySocket = _listener.AcceptSocket();
if (mySocket.Connected)
{
StringBuilder sb = new StringBuilder();
Byte[] bReceive = new Byte[1024];
int i;
while ((i = mySocket.Receive(bReceive, bReceive.Length, 0) > 0))
{
sb.Append(Encoding.ASCII.GetString(bReceive, 0, i)); // added index and count
}
string sBuffer = sb.ToString();
if (sBuffer.Substring(0, 3) != "GET")
{
Console.WriteLine(sBuffer);
mySocket.Close();
return;
}
}
}
Related
I am using sockets for TCP-IP connection and I would like to establish simple system send-receive from the client side.
Socket sck;
sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint localEndpt = new IPEndPoint(IPAddress.Parse("123.123.123.1"), 12345);
try
{
sck.Connect(localEndpt);
}
catch
{
Console.Write("Unable to Connect");
}
while (true)
{
Console.WriteLine("Enter Text");
string sendtext = Console.ReadLine();
byte[] Data = Encoding.ASCII.GetBytes(sendtext);
sck.Send(Data);
Console.WriteLine("Data Sent!");
byte[] bytesReceived = new byte[sck.ReceiveBufferSize];
int bytes = 0;
String strReceived = "";
int dataAvailable = 0;
while (dataAvailable == 0 || dataAvailable != sck.Available)
{
dataAvailable = sck.Available;
Thread.Sleep(100); // if no new data after 100ms assume transmission finished
}
if (sck.Available > 0)
{
bytes = sck.Receive(bytesReceived, bytesReceived.Length, 0);
strReceived+=Encoding.ASCII.GetString(bytesReceived, 0, bytes);
}
Console.WriteLine("Received from server: " + strReceived);
}
Console.Read();
The problem is that first requests goes throught but the second does not, because socket is not available anymore (socket "Availabe" attribute value is 0). What am I doing wrong? What would be the easiest way to establish multiple send-recieve requests (in order)?
This code works fine for me
private List<Socket> _clients = new List<Socket>();
private Thread _dataReceiveThread;
private bool _isConnected;
private void DataReceive()
{
while (_isConnected)
{
List<Socket> clients = new List<Socket>(_clients);
foreach (Socket client in clients)
{
try
{
if (!client.Connected) continue;
string txt = "";
while (client.Available > 0)
{
byte[] bytes = new byte[client.ReceiveBufferSize];
int byteRec = client.Receive(bytes);
if (byteRec > 0)
txt += Encoding.UTF8.GetString(bytes, 0, byteRec);
}
if (!string.IsNullOrEmpty(txt))
/* TODO: access the text received with "txt" */
}
catch (Exception e)
{
Exception_Handler(e);
}
}
}
}
Just run this code to get started
_isConnected = true;
_dataReceiveThread = new Thread(DataReceive);
_dataReceiveThread.Start();
Update list box in Cross thread:
This code can be placed in the comment section.
myListBox1.Invoke((Action)(() => { myListBox1.Items.Add(txt) }));
Socket. Available does NOT indicate whether the socket is available, but incoming data is available for reading:
https://msdn.microsoft.com/en-us/library/ee425135.aspx
Your program quits because it checks for a reply (incoming data) immediately after sending a message out. Use a Thread.Sleep before checking for data.
Maybe the message has not even been sent, because Socket.Send just places it in the network interface card's output buffer. When the socket finally sends the message, it will upare the connection state. If it got no reply (on a TCP connection), it will tell you that it is disconnected when you query the state. On UDP it will tell you nothing, because UDP is connectionless.
I'm connecting to a server that talks in a JSON protocol. It sends each bit of information as a JSON object. Here are three examples.
{"from":"SERVER","code":"SERVER_OK"}
{"from":"SERVER","code":"CHAT_JOIN","data":{"room":"Lobby"}}
{"from":"SERVER","code":"PING","data":{"time":1405901428001}}
My C# code looks like this.
void Start () {
clientSocket = new TcpClient();
clientSocket.Connect("127.0.0.1", 5000);
serverStream = clientSocket.GetStream();
serverStream.BeginRead(buffer, 0, buffer.Length, ReadComplete, buffer);
}
void ReadComplete (IAsyncResult iar) {
buffer = (byte[])iar.AsyncState;
int bytesAvailable = serverStream.EndRead(iar);
string data = System.Text.Encoding.UTF8.GetString(buffer);
Array.Clear(buffer, 0, 4096);
serverStream.BeginRead(buffer, 0, buffer.Length, ReadComplete, buffer);
Debug.Log(data);
}
My debug log looks like this:
{"from":"SERVER","code":"SERVER_OK"}{"from":"SERVER","code":"CHAT_JOIN","data":{"room":"Lobby"}}
{"from":"SERVER","code":"PING","data":{"time":1405901428001}}
{"from":"SERVER","code":"PING","data":{"time":1405901433001}}
{"from":"SERVER","code":"PING","data":{"time":1405901438004}}
It looks like I can receive more than one JSON object at a time in each ReadComplete. I also assume I could receive a partial JSON object as well. What do I need to do to be able to process a single JSON object at a time? I'm guessing I have to concatenate each received chunk of data to a string and the chop off the front of it each object one at a time. I just have no idea how to go about doing that.
I ended up moving into a Thread and processing the stream one byte at a time looking for the JSON object boundaries. For each on I try to parse it and add it a Queue for the parent thread to process.
So far this seems to work without causing any threading issues with the rest of my application and has been working well with the overall performance for my needs.
// The network thread listening to the server
private void NetworkThread () {
Debug.Log("Connecting to server...");
clientSocket = new TcpClient();
clientSocket.Connect("127.0.0.1", 5000);
stream = clientSocket.GetStream();
int braces = 0;
bool inQ = false;
char lastB = ' ';
while (!stopThread) {
char b = (char)stream.ReadByte();
if (b < 0)
return;
buffer.Append((char)b);
if (b == '"' && lastB != '\\') {
inQ = !inQ;
}
else if (b == '{' && !inQ) {
braces += 1;
}
else if (b == '}' && !inQ) {
braces -= 1;
}
lastB = (char)b;
if (braces == 0) {
try {
JSONNode packet = JSONNode.Parse(buffer.ToString());
buffer = new StringBuilder();
lock (lockQueue) {
packetQueue.Enqueue(packet);
}
} catch (Exception e) {
}
}
}
}
Instat of manually reciving the data use Streamreader and it's .ReadLine() method. It looks like the server sends line for line, so it should not be a problem to read response for response.
I send 2 successive packets from my client to the server who is listening using BeginReceive
The server always receives the first packet but not the other EXCEPT if I run the client in debug mode and slowly send the next packet after the other.
Here's a snippet from my sending function
if (soc.Connected)
{
byte[] byData = new byte[System.Text.Encoding.ASCII.GetByteCount("Hi")];
byData = System.Text.Encoding.ASCII.GetBytes("Hi");
soc.Send(BitConverter.GetBytes(byData.Length));
soc.Send(byData);
}
And here's is my call back function located inside of my server:
private void Recieve(IAsyncResult iar)
{
int j = 0;
Socket server_conn = (Socket)iar.AsyncState;
server_conn.EndReceive(iar);
if (!SocketConnected(server_conn))
{
server_conn.Close();
return;
}
if (g_bmsg.Length != 0)
{
logthis(server_conn.RemoteEndPoint.ToString() + ": " + Encoding.ASCII.GetString(g_bmsg, 0, g_bmsg.Length));
}
//Find out who sent this
foreach (ClientData cls in clientlist)
{
if (server_conn.RemoteEndPoint == cls.clientsock.RemoteEndPoint)
{
j = cls.index;
break;
}
}
server_conn.BeginReceive(g_bmsg, 0, g_bmsg.Length, SocketFlags.None, new AsyncCallback(Recieve), server_conn);
}
When working with TCP/IP sockets (or pretty much any communication layer), you rarely have a guarantee that the entire message you intended to send will come in a single packet.
This means that you should always keep a FIFO buffer of your own, and parse it sequentially.
This is the general idea:
// fifo queue (for background thread parsing, make sure it's thread safe)
private readonly ConcurrentQueue<byte> _commQueue = new ConcurrentQueue<byte>();
In your Receive method, you should simply enqueue the data to the FIFO:
private void Receive(IAsyncResult iar)
{
Socket server_conn = (Socket)iar.AsyncState;
// check how many bytes we actually received
var numBytesReceived = server_conn.EndReceive(iar);
if (!SocketConnected(server_conn))
{
server_conn.Close();
return;
}
// get the received data from the buffer
if (numBytesReceived > 0)
{
for (int i = 0; i < numBytesReceived; i++)
_commQueue.Enqueue(g_bmsg[i]);
// signal the parser to continue parsing
NotifyNewDataReceived();
}
// continue receiving
server_conn.BeginReceive(g_bmsg, 0, g_bmsg.Length, SocketFlags.None, new AsyncCallback(Recieve), server_conn);
}
Good afternoon. I apologize for my English as itself from Ukraine and speak badly)) I have the following problem, my program makes requests on different urls and then parse some info from answers. Number of urls are more than several millions. To quickly process I use a lot of threads, sometimes about 500-700 threads. On some machines program is running well, but there are those on which errors occur. Errors like: System.Net.Sockets.SocketException (0x80004005): The remote host forcibly broke the existing connection.
My code:
void _thread()
{
while(true)
{
string request =
"POST http://" + hostf + "/ HTTP/1.1\r\n" +
"Host: " + host +
"\r\nConnection: Close\r\n" +
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" +
"Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3\r\n" +
"Content-Length: " + ByteArr.Length +
"\r\nContent-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n\r\n" +
parametres;
Byte[] bytesSent = Encoding.GetEncoding("UTF-8").GetBytes(request);
Byte[] bytesReceived = new Byte[256];
Socket s = null;
IPHostEntry hostEntry = null;
hostEntry = Dns.GetHostEntry(host);
foreach (IPAddress address in hostEntry.AddressList)
{
IPEndPoint ipe = new IPEndPoint(address, 80);
Socket tempSocket =new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
tempSocket.Connect(ipe);
if (tempSocket.Connected)
{
s = tempSocket;
break;
}
else
{
continue;
}
}
if (s == null)
continue;
s.Send(bytesSent, bytesSent.Length, 0);
int bytes = 0;
string page = "";
do
{
bytes = s.Receive(bytesReceived, bytesReceived.Length, 0);
page = page + Encoding.GetEncoding("UTF-8").GetString(bytesReceived, 0, bytes);
}
while (bytes > 0);
s.Shutdown(SocketShutdown.Both);
s.Close();
//here some work whith page content
}
}
As you see, each thread creates socket, sends request, then get answer and closes socket and so on with each iteration. Each thread opens its own socket and works with different urls, but on some machines when numbers of threads are more than some number, the errors begin and all sockets don't work normally. Could someone help me with some advise, why does it happen? Some machines have some kind of limits on connection or what? Thank you all in advance.
Dont do the shutdown(both); followed by a close. Remove the s.shutdown() and leave the s.Close() then try. I think I remeber that shutdown both makes the socket descriptor available for use so in the next close you can be closing some other socket instead the one you owned.
EDIT: some code modification:
I'd increment a little bit the receive buffer
bytes[] bytesReceived = new bytes[1024];
Also when sending the request string tell the reciver you are done:
s.Send(bytesSent, bytesSent.Length, 0);
// Tell the receiver we are done sending data
s.Shutdown(SocketShutdown.Send);
You also have to check for error when reading the socket and use a StringBuilder instead of a String (it's somehow faster than String appending text):
StringBuilder page = new StringBuilder();
do
{
bytes = s.Receive(bytesReceived, bytesReceived.Length, 0);
if (bytes == -1)
{
// Error in socket, quit
s.Close();
return;
}
else if (bytes > 0)
page.Append(Encoding.GetEncoding("UTF-8").GetString(bytesReceived, 0, bytes));
}
while (bytes > 0);
At the end, just close the socket:
// s.ShutDown(Socketshutdown.Both);
s.close();
You may try with this modifications and see if it is solved.
I developed a simple TCP client on Windows Phone, as shown here on MSDN
This is working just as expected.
Now, I want to send very large Base64 strings though this client (for transferring images).
But, when I try to send Base64 strings from this client, I only receive a portion of the string at the server, due to which I'm not able to generate the entire image at the server.
The server side code for receiving strings is: (Edited)
IPAddress ipAd = IPAddress.Any;
Console.Write("Port No. (leave blank for port 8001): ");
string port;
port = Console.ReadLine();
if (port == "")
port = "8001";
/* Initializes the Listener */
TcpListener myList = new TcpListener(ipAd, int.Parse(port));
/* Start Listeneting at the specified port */
myList.Start();
Console.WriteLine("\nThe server is running at port " + port);
Console.WriteLine("The local End point is :" +
myList.LocalEndpoint);
Console.WriteLine("\nWaiting for a connection.....");
Socket s = myList.AcceptSocket();
Console.WriteLine("\nConnection accepted from " + s.RemoteEndPoint);
byte[] b = new byte[5 * 1024 * 1024]; // BIG SIZE for byte array, is this correct?
String message = String.Empty;
int k = s.Receive(b);
Console.WriteLine("\nRecieved...");
for (int i = 0; i < k; i++)
{
message += Convert.ToChar(b[i]);
Console.Write(Convert.ToChar(b[i]));
}
System.IO.File.WriteAllText(#"Message.txt", message); // write it to a file
ASCIIEncoding asen = new ASCIIEncoding();
s.Send(asen.GetBytes("The string was recieved by the server."));
Console.WriteLine("\n\nSent Acknowledgement");
/* clean up */
s.Close();
myList.Stop();
I'm really stuck here.
Please help me.
I think the problem is with the client and not the server.
Please assist me.
The class I've used in the client can be found at the MSDN article referred to above.
PS: I've already tried to increase the values of TIMEOUT_MILLISECONDS and MAX_BUFFER_SIZE in the class. But it did not help.
Update:
Here's some client side code (look here on MSDN for reference):
// Make sure we can perform this action with valid data
if (ValidateRemoteHost() && ValidateInput())
{
// Instantiate the SocketClient
SocketClient client = new SocketClient();
// Attempt to connect to the echo server
Log(String.Format("Connecting to server '{0}' over port {1} (echo) ...", txtRemoteHost.Text, ECHO_PORT), true);
string result = client.Connect(txtRemoteHost.Text, ECHO_PORT);
Log(result, false);
byte[] bytearray = null;
// Attempt to send our message to be echoed to the echo server
Log(String.Format("Sending '{0}' to server ...", txtInput.Text), true);
if (checkBox1.IsChecked == true) // this checkbox is for image selection
{
// This is the part where we send images
using (MemoryStream ms = new MemoryStream())
{
WriteableBitmap wbitmp = new WriteableBitmap((BitmapImage)image1.Source);
wbitmp.SaveJpeg(ms, (int)wbitmp.PixelWidth, (int)wbitmp.PixelHeight, 0, 10);
bytearray = ms.ToArray();
string str = Convert.ToBase64String(bytearray);
result = client.Send(str);
System.Diagnostics.Debug.WriteLine("\n\nMessge sent:\n\n" + str + "\n\n");
}
}
else
{
result = client.Send(txtInput.Text);
}
Log(result, false);
// Receive a response from the server
Log("Requesting Receive ...", true);
result = client.Receive();
Log(result, false);
// Close the socket connection explicitly
client.Close();
}
while ((RecBytes = netstream.Read(RecData, 0, RecData.Length)) > 0)
{
Fs.Write(RecData, 0, RecBytes);
totalrecbytes += RecBytes;
}
Edit: now that section of code has been reduced down to only
int k = s.Receive(b);
is bad: it assumes all the data sends perfectly in one go, which isn't how networking works.
Two options:
At the start of the string, include how long it should.
At the end of the string, have an end symbol (a null perhaps) that won't be anywhere else in the message
Then that while loop should keep going until either the entire length is found or the end symbol is found.
(Also, sending Base64 is a bad idea when you can avoid it. Why not send as a stream of raw bytes?)
[ED: This portion is no longer relevant](Also, why is the server choosing where to save the file [and delaying everything until the server makes a pick] - the client should indicate where to save it at the start, and then the server merely sanity checks it. [Unless you have a very good reason not do it that way])
EDIT: a quick simple implementation of what I was saying:
This server code
int k = s.Receive(b);
Console.WriteLine("\nRecieved...");
for (int i = 0; i < k; i++)
{
message += Convert.ToChar(b[i]);
Console.Write(Convert.ToChar(b[i]));
}
change to
while (true)
{
int k = s.Receive(b);
Console.WriteLine("\nRecieved...");
for (int i = 0; i < k; i++)
{
char bc = Convert.ToChar(b[i]); // This is a very wrong way of doing this but it works I guess meh.
if (bc == ' ')
{ // You've struck the end! Get out of this infinite loop!
goto endmyloop;
}
message += bc;
Console.Write(bc);
}
}
endmyloop:
This piece of client code
result = client.Send(str);
change to
result = client.Send(str + " ");
-- Base64 can never have a space in it, so that will be used to mark the end.
Be warned that if the client errors (and doesn't send a space at the end for some weird reason), this code will be trapped in the while loop forever (zero-CPU-usage infinite-wait)