Simple Asynchronous TCP Chat Application [C#] - c#

Ok, I studied a bit on asynchronous TCP network connection. I tried making one but failed. What I want to do is make sure the server or client is always ready to receive a chat and is able to send a chat any time. I do not want them to be on alternate mode.
e.g. Server Send while client waits to receive thus client can't send at that time.
I do not want that!
Did this on Windows Application. Once I connected, the system resource just shot to 100% =/
Server Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
namespace AsyncServerChat
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private Socket g_server_conn;
private byte[] g_bmsg;
private bool check = false;
private void Form1_Load(object sender, EventArgs e)
{
IPEndPoint local_ep = new IPEndPoint(IPAddress.Any, 9050);
Socket winsock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
winsock.Bind(local_ep);
winsock.Listen(5);
winsock.BeginAccept(new AsyncCallback(Accept), winsock);
}
private void Accept(IAsyncResult iar)
{
Socket server_conn =(Socket) iar.AsyncState;
g_server_conn = server_conn.EndAccept(iar);
//label1.Text = "Connected. . .";
while (g_server_conn.Connected && check == false)
{
g_bmsg = new byte[1024];
check = true;
g_server_conn.BeginReceive(g_bmsg, 0, g_bmsg.Length, SocketFlags.None, new AsyncCallback(Recieve), g_server_conn);
}
}
private void Send(IAsyncResult iar)
{
Socket server_conn = (Socket)iar.AsyncState;
server_conn.EndSend(iar);
}
private void Recieve(IAsyncResult iar)
{
Socket server_conn =(Socket) iar.AsyncState;
server_conn.EndReceive(iar);
if (g_bmsg.Length != 0)
{
label1.Text = Encoding.ASCII.GetString(g_bmsg, 0, g_bmsg.Length);
check = false;
}
}
private void sendButton_Click(object sender, EventArgs e)
{
string strmsg = textBox1.Text;
byte[] bmsg= Encoding.ASCII.GetBytes(strmsg);
g_server_conn.BeginSend(bmsg, 0, bmsg.Length, SocketFlags.None, new AsyncCallback(Send), g_server_conn);
}
}
}
Client
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
namespace AsyncClientChat
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Socket g_client_conn;
byte[] g_bmsg;
private bool check = false;
private void Form1_Load(object sender, EventArgs e)
{
}
private void connectButton_Click(object sender, EventArgs e)
{
IPEndPoint remote_ep = new IPEndPoint(IPAddress.Parse(textBox1.Text), 9050);
g_client_conn = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
g_client_conn.BeginConnect(remote_ep, new AsyncCallback(Connect), g_client_conn);
}
private void Connect(IAsyncResult iar)
{
Socket client_conn =(Socket) iar.AsyncState;
client_conn.EndConnect(iar);
while (g_client_conn.Connected)
{
g_bmsg = new byte[1024];
check = true;
g_client_conn.BeginReceive(g_bmsg, 0, g_bmsg.Length, SocketFlags.None, new AsyncCallback(Recieve), g_client_conn);
}
}
private void Send(IAsyncResult iar)
{
Socket client_conn = (Socket)iar.AsyncState;
client_conn.EndSend(iar);
}
private void Recieve(IAsyncResult iar)
{
Socket client_conn = (Socket)iar.AsyncState;
client_conn.EndReceive(iar);
if (g_bmsg.Length != 0)
{
label1.Text = Encoding.ASCII.GetString(g_bmsg, 0, g_bmsg.Length);
check = false;
}
}
}
}

Well, the problem is the while loop in client method Connect.
Remove it because it loops infinitely raising CPU usage to 100% and it's useless.
BTW, you have another problems in your code:
CrossThread operation exception
For example in your Client.Recieve method you do:
label1.Text = Encoding.ASCII.GetString(g_bmsg, 0, g_bmsg.Length);
Actually, you're trying to set the label text from another thread (the one listening for received msgs) and this is not allowed;
Do something like this:
Create a Setter method for the label text:
private void SetLabelText(string txt)
{
if (label1.InvokeRequired)
label1.Invoke(new MethodInvoker(delegate { SetLabelText1(txt); }));
else
label1.Text = txt;
}
then use the setter instead of directly call label1.Text = ...:
SetLabelText(Encoding.ASCII.GetString(g_bmsg, 0, g_bmsg.Length));
EDIT to answer to OP comment:
For a good and extensive explanation of what is a thread, look at its wikipedia page.
Anyway, in simple words, a running process contains one or more threads and these are part of code that can be executed concurrently.
Starting from your TCP example, using Socket.Receive instead of Socket.BeginReceive you would have blocked the execution on Socket.Receive() call (I mean the lines of code after the one containing Receive method wouldn't be reached) until something is received.
This because Socket.Receive method runs on the same thread of the following code, and on each thread, the code is executed sequentially (i.e. line by line).
Conversely, using Socket.BeginReceive, behind the scene a new thread is created. This thread likely calls and stops on Socket.Receive method, and once received something it calls the method passed as parameter.
This makes Socket.BeginReceive asynchronous, while Socket.Receive is synchronous, and this is why I knew ther was another thread (when you hear asynchronous word, is extremely probable that you are dealing with multi-threading)
Thus, when you change label.Text you are actually setting it from another thread: the one created by Socket.BeginReceive.

I took a quick look at this code and I would start with the following suggestion.
Remove the looping from your Accept callback, just initiate the BeginReceive and let it be. Then in your Receive method, you can just initiate the next BeginReceive. This would apply for both the client and the server code, except of course for the client code you will remove the loop from your Connect callback method.
Then you should also watch out updating the UI controls from the callback methods, since the callback runs on the non-UI thread which can cause a host of problems. You should look at using Control.Invoke or Control.BeginInvoke to marshal a request back to the UI thread which can then update the controls.

Related

Listen to message from an IP from another machine

I am trying to send a message to Unity through UDP. The machine that sends the message has IP as 192.16.14.1 and port as 3034. How do I enter these two inside of Unity application? I have found a code to listen for UDP messages but I cannot set the IP address here. Also the Unity application should be running at all times even if the message from another machine is sent or not.
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using UnityEngine;
public class UDP_Listen : MonoBehaviour
{
UdpClient clientData;
int portData = 3034;
public int receiveBufferSize = 120000;
public bool showDebug = false;
IPEndPoint ipEndPointData;
private object obj = null;
private System.AsyncCallback AC;
byte[] receivedBytes;
void Start()
{
InitializeUDPListener();
}
public void InitializeUDPListener()
{
ipEndPointData = new IPEndPoint(IPAddress.Any, portData);
clientData = new UdpClient();
clientData.Client.ReceiveBufferSize = receiveBufferSize;
clientData.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, optionValue: true);
clientData.ExclusiveAddressUse = false;
clientData.EnableBroadcast = true;
clientData.Client.Bind(ipEndPointData);
clientData.DontFragment = true;
if (showDebug) Debug.Log("BufSize: " + clientData.Client.ReceiveBufferSize);
AC = new System.AsyncCallback(ReceivedUDPPacket);
clientData.BeginReceive(AC, obj);
Debug.Log("UDP - Start Receiving..");
}
void ReceivedUDPPacket(System.IAsyncResult result)
{
//stopwatch.Start();
receivedBytes = clientData.EndReceive(result, ref ipEndPointData);
ParsePacket();
clientData.BeginReceive(AC, obj);
//stopwatch.Stop();
//Debug.Log(stopwatch.ElapsedTicks);
//stopwatch.Reset();
} // ReceiveCallBack
void ParsePacket()
{
// work with receivedBytes
Debug.Log("receivedBytes len = " + receivedBytes.Length);
}
void OnDestroy()
{
if (clientData != null)
{
clientData.Close();
}
}
}
If the Unity application is to be receiving the messages constantly, it needs to be something like:
UdpClient listener = new UdpClient(11000);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Parse("192.16.14.1"), 3034);
while (true)
{
byte[] bytes = listener.Receive(ref groupEP);
}
This should read only calls from the specific IP, not sure which port you want the UDPClient to read out from (specified in the UDPClient constructor) but you can set this to whatever you need it to be.
So there are two different things:
You want to define the receiving local port you Bind your socket to
You want to define the expected sending remote ip + port you want to Receive from
Currently you are using the very same one
ipEndPointData = new IPEndPoint(IPAddress.Any, portData);
for both! (Fun fact: As a side effect by using always the same field you basically allow any sender but are then bond to that specific sender from this moment on)
Actually a lot of things you configure there are the default values anyway so here is more or less what I would do
using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UnityEngine;
public class UDP_Listen : MonoBehaviour
{
public ushort localReceiverPort = 3034;
public string senderIP = "192.168.111.1";
public ushort remoteSenderPort = 3034;
public bool showDebug = false;
// Thread-safe Queue to handle enqueued actions in the Unity main thread
private readonly ConcurrentQueue<Action> mainThreadActions = new ConcurrentQueue<Action>();
private Thread udpListenerThread;
private void Start()
{
// do your things completely asynchronous in a background thread
udpListenerThread = new Thread(UDPListenerThread);
udpListenerThread.Start();
}
private void Update()
{
// in the Unity main thread work off the actions
while (mainThreadActions.TryDequeue(out var action))
{
action?.Invoke();
}
}
private void UDPListenerThread()
{
UdpClient udpClient = null;
try
{
// local end point listens on any local IP
var localEndpoint = new IPEndPoint(IPAddress.Any, localReceiverPort);
udpClient = new UdpClient(localEndpoint);
if (showDebug)
{
Debug.Log("BufSize: " + clientData.Client.ReceiveBufferSize);
}
Debug.Log("UDP - Start Receiving..");
// endless loop -> ok since in a thread and containing blocking call(s)
while (true)
{
// remote sender endpoint -> listens only to specific IP
var expectedSenderEndpoint = new IPEndPoint(IPAddress.Parse(senderIP), remoteSenderPort);
// blocking call - but doesn't matter since this is a thread
var receivedBytes = udpClient.Receive(ref expectedSenderEndpoint);
// parse the bytes here
// do any expensive work while still on a background thread
mainThreadActions.Enqueue(() =>
{
// Put anything in here that is required to happen in the Unity main thread
// so basically anything using GameObject, Transform, etc
});
}
}
// thrown for "Abort"
catch (ThreadAbortException)
{
Debug.Log("UDP Listener terminated");
}
// Catch but Log any other exception
catch (Exception e)
{
Debug.LogException(e);
}
// This is run even if an exception happend
finally
{
// either way dispose the UDP client
udpClient?.Dispose();
}
}
private void OnDestroy()
{
udpListenerThread?.Abort();
}
}
I'm sure the same can be done also using the BeginReceive/EndReceive or task based alternatives but since it is going to run endless anyway I personally find a thread often easier to read and maintain.
I think you got it backwards. This code you shared is for, like you said, listen UDP protocol on desired port. This piece of code needs to be inside your "server". By server try to understand that as the receiving side.
on your shared method InitializeUDPListener(); we have this piece:
ipEndPointData = new IPEndPoint(IPAddress.Any, portData);
this means you are initializing your udp socket to listen for ANY ip adresses at the given port. That said, you have your server ready to go, what you need to do is setup the client side, the one who sends the message.
here some example:
public string serverIp = "127.0.0.1"; // your server ip, this one is sending to local host
public int serverPort = 28500; // your server port
public void ClientSendMessage()
{
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPAddress broadcast = IPAddress.Parse(serverIp);
byte[] sendbuf = Encoding.ASCII.GetBytes("THIS IS A MESSAGE FROM CLIENT!");
IPEndPoint ep = new IPEndPoint(broadcast, serverPort);
s.SendTo(sendbuf, ep);
}
I encourage you to read about UDP/TCP protocols before using them. MS has documentation with details.
here some links:
TCP
UDP
Sockets

Why is my object being used by another thread? [duplicate]

This question already has answers here:
The calling thread cannot access this object because a different thread owns it
(15 answers)
Closed 6 years ago.
When ever I press the send button the TCP Client, it stops the TCP Server and throws me this error.
The calling thread cannot access this object because a different
thread owns it.
I've tried debugging it but couldnt find the issue.
How would I be able to fix this since it is bugging me alot and I am new to TCP / IP and threading aswell.
I know how it works but yeah.
In the listenerThread() method its this line that is throwing me this error.
lbConnections.Items.Add(handlerSocket.RemoteEndPoint.ToString() + " connected.");
using System;
using System.Collections;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows;
using System.Windows.Forms;
using System.Text;
namespace SimpleTCPServer
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ArrayList nSockets;
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
IPHostEntry IPHost = Dns.GetHostByName(Dns.GetHostName());
lblStatus.Content = "My IP address is " + IPHost.AddressList[0].ToString();
nSockets = new ArrayList();
Thread thdListener = new Thread(new ThreadStart(listenerThread));
thdListener.Start();
}
public void listenerThread()
{
TcpListener tcpListener = new TcpListener(8080);
tcpListener.Start();
while (true)
{
Socket handlerSocket = tcpListener.AcceptSocket();
if (handlerSocket.Connected)
{
Control.CheckForIllegalCrossThreadCalls = false;
lbConnections.Items.Add(handlerSocket.RemoteEndPoint.ToString() + " connected.");
lock (this)
{
nSockets.Add(handlerSocket);
}
ThreadStart thdstHandler = new
ThreadStart(handlerThread);
Thread thdHandler = new Thread(thdstHandler);
thdHandler.Start();
}
}
}
public void handlerThread()
{
Socket handlerSocket = (Socket)nSockets[nSockets.Count - 1];
NetworkStream networkStream = new NetworkStream(handlerSocket);
int thisRead = 0;
int blockSize = 1024;
Byte[] dataByte = new Byte[blockSize];
lock (this)
{
// Only one process can access
// the same file at any given time
Stream fileStream = File.OpenWrite("c:\\my documents\\SubmittedFile.txt");
while (true)
{
thisRead = networkStream.Read(dataByte, 0, blockSize);
fileStream.Write(dataByte, 0, thisRead);
if (thisRead == 0) break;
}
fileStream.Close();
}
lbConnections.Items.Add("File Written");
handlerSocket = null;
}
}
}
TCP Client
using Microsoft.Win32;
using System.IO;
using System.Net.Sockets;
using System.Windows;
using System.Threading;
using System.Net;
using System.Text;
namespace SimpleTCPClient
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void browseButton_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
if (openFileDialog.ShowDialog() == true)
fileTextbox.Text = (openFileDialog.FileName);
}
private void btnSend_Click(object sender, RoutedEventArgs e)
{
Stream fileStream = File.OpenRead(fileTextbox.Text);
// Alocate memory space for the file
byte[] fileBuffer = new byte[fileStream.Length];
fileStream.Read(fileBuffer, 0, (int)fileStream.Length);
// Open a TCP/IP Connection and send the data
TcpClient clientSocket = new TcpClient(ipTextbox.Text, 8080);
NetworkStream networkStream = clientSocket.GetStream();
networkStream.Write(fileBuffer, 0, fileBuffer.GetLength(0));
networkStream.Close();
}
}
}
if lbConnections is a client control, you cannot modify it from a background thread - you must invoke a method that will do the updating on the GUI thread. There's effectively no thread safety around GUI controls, and all disabling Control.CheckForIllegalCrossThreadCalls does is make it less obvious when you shoot yourself in the foot.
In general, you have other problems. For example, your handler thread always tries to grab the last connection - there's a very real possibility that two connections could happen (and both be added to nSockets) before either of the handler threads try to grab the sockets - meaning one socket never gets grabbed and one gets grabbed twice. Plus, it looks like you never actually dispose any of the socket objects, or even allow them to be GCd, since I don't see any code that removes from nSockets.
You really have two good options - either pass the handler thread the data it needs, or use something like a queue and have the handler thread dequeue one socket and operate on it (of course all queue access must be synchronized). Either way you should be disposing of the sockets and not keeping them around forever.

C# Chat application freezes when code is executed

so I have been working on my chat application in c# as a windows form application and when this code to receive data has to be executed the program freezes.
Anyone help me please, finding out whats wrong about this. As a console application it works.
UdpClient udpClient = new UdpClient(Convert.ToInt32(textPort.Text));
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
string returnData = Encoding.ASCII.GetString(receiveBytes);
textMsg.Text = returnData.ToString();
Your program is frozen because the UdpClient class's Receive(...) method is blocking.
That is to say, it will stop at that point of execution and not allow the thread/process it is in to continue until it receives a single UDP packet. This includes the UI unless you put this in a separate thread or us an asynchronous communication model.
If you want to handle communications asynchronously, check out the BeginReceive(...) method.
And here is some example code (Originally, I was using this codestraight from Microsoft. However, it was missing the definition for UdpState. After some teeth gnashing, I figured out you had to create it to pass your own state in so the asynchronous model would work as expected. The example has been updated and compiles in VS2008, .Net 3.5):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace ConsoleApplication1
{
class UdpState
{
public IPEndPoint e = null;
public UdpClient u = null;
}
class Program
{
public static bool messageReceived = false;
public static void ReceiveCallback(IAsyncResult ar)
{
UdpClient u = (UdpClient)((UdpState)(ar.AsyncState)).u;
IPEndPoint e = (IPEndPoint)((UdpState)(ar.AsyncState)).e;
Byte[] receiveBytes = u.EndReceive(ar, ref e);
string receiveString = Encoding.ASCII.GetString(receiveBytes);
Console.WriteLine("Received: {0}", receiveString);
messageReceived = true;
}
public static void ReceiveMessages(int listenPort)
{
// Receive a message and write it to the console.
IPEndPoint e = new IPEndPoint(IPAddress.Any, listenPort);
UdpClient u = new UdpClient(e);
UdpState s = new UdpState();
s.e = e;
s.u = u;
Console.WriteLine("listening for messages");
u.BeginReceive(new AsyncCallback(ReceiveCallback), s);
// Do some work while we wait for a message. For this example,
// we'll just sleep
while (!messageReceived)
{
Thread.Sleep(100);
}
}
static void Main(string[] args)
{
ReceiveMessages(10000);
}
}
}
Was this helpful?
You should investigate how threading works.
In windows forms you could use BackgroundWorker
On msdn you can even find a working sample code.
PS: be sure not to call UI controls directly in the DoWork event (it runs on another thread). If you really need to, invoke it through the Invoke method that exists in every windows forms control.

WPF C# application will freeze my whole computer ever 2-3 times I run it

I put a lot of information in this issue because I have no idea what will be relavent
Issue:
I am having an issue with a program I am working on where when running it, it will freeze my whole computer and return no error (I am completely incapable of doing anything CTRL+ALT+DEL doesn't even work). This program accepts a connection from a android client and atm the android client is not configured correctly so the connection is being rejected.
Question:
How can I stop my program from freezing my entire machine?
Conjecture:
I have a few theories as to what is going on but no idea how to fix them. I have read that this may have something to do with me running a single threaded process inside my async worker but I am not sure that the socket is a single threaded process. Also I am not entirely sure how I am supposed to deal with exceptions in a backgroundworker so I just let it fall back to the RunWorkerCompletedEventArgs then retrieve the error message from there.
What I have tried:
- I tried putting try catches every where then removing try catches nothing seems to be able to capture this error
- I checked my systems event log and nothing is showing up except my restarts after my computer freezes
- I have attempted to isolate the issue but it can literally happen at any point from the program starting till when I attempt to connect
Setup:
I am running the program out of visual studio 2012 professional on a windows 8 pro machine. The computer I am on has a i7-3770K 3.50GHz and 32GB of ram. The application that is attempting to make a connection to mine is a Android application and the credentials are incorrect when it is attempting to connect. Visual Studio is running off my main hard drive and building the project on another drive.
Closing:
With all that said would some one please be willing to help me? If you need any more information I will be happy to provide it, please ask.
Main Method:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
namespace Server
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class SourceServer : Window
{
private BackgroundWorker worker = new BackgroundWorker();
public SourceServer()
{
InitializeComponent();
StartListeningForConnections();
}
private void StartListeningForConnections()
{
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
worker.WorkerReportsProgress = true;
if (worker.IsBusy != true)
{
worker.RunWorkerAsync();
}
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
worker.ReportProgress(0, "Source server version 0.0.0.1ib started");
LoginServer oLoginServer = new LoginServer();
oLoginServer.StartListening(worker);
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
try
{
lvOutput.Items.Add(e.UserState.ToString());
}
catch (Exception exception)
{
lvOutput.Items.Add(exception.StackTrace);
}
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
System.IO.File.WriteAllText(Environment.CurrentDirectory + #"\log.txt", e.Error.StackTrace + " /n " + e.Error.Message);
}
else
{
MessageBox.Show("Error was null");
}
worker.Dispose();
}
}
}
SSL Socket Connection:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using MySql.Data.MySqlClient;
using System.IO;
namespace Server
{
public class LoginServer
{
// Incoming data from the client.
public static string data = null;
public static X509Certificate serverCertificate = null;
public delegate void UpdateListView(ListView oOutput);
public void StartListening(BackgroundWorker worker)
{
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[1];
serverCertificate = X509Certificate.CreateFromCertFile(#"server.crt");
TcpListener oServer = new TcpListener(ipAddress, 12345);
// Bind the socket to the local endpoint and
// listen for incoming connections.
// Start listening for connections.
while (true)
{
Thread.Sleep(100);
worker.ReportProgress(0, "Waiting for connection....");
// Program is suspended while waiting for an incoming connection.
//Socket handler = listener.Accept();
oServer.Start();
TcpClient oClient = oServer.AcceptTcpClient();
Stream oStream = oClient.GetStream();
SslStream oSSLStream = new SslStream(oStream);
data = null;
// An incoming connection needs to be processed.
string sUsername = "place holder";
string sPassword = "place holder";
while (true)
{
bytes = new byte[1024];
int bytesRec = oSSLStream.Read(bytes, 0, bytes.Length);
data += Encoding.ASCII.GetString(bytes, 0, bytesRec);
string[] sCredentials = data.Split("|".ToCharArray()[0]);
sUsername = sCredentials[0];
sPassword = sCredentials[1];
if (data.IndexOf("<EOF>") > -1)
{
break;
}
}
// Show the data on the console.
worker.ReportProgress(0, "Connection Recieved : ");
worker.ReportProgress(0, "Username: " + sUsername);
worker.ReportProgress(0, "Password: " + sPassword);
worker.ReportProgress(0, "");
// Echo the data back to the client.
byte[] msg;
if (sUsername.Equals("test") && sPassword.Equals("test"))
{
msg = Encoding.ASCII.GetBytes("approved<EOF>\n");
worker.ReportProgress(0, "approved");
oSSLStream.Write(msg, 0, msg.Length);
}
else
{
msg = Encoding.ASCII.GetBytes("rejected<EOF>\n");
worker.ReportProgress(0, "rejected");
oSSLStream.Write(msg, 0, msg.Length);
}
}
}
public void VerifyUser()
{
}
}
}
While I don't see any reason for this to lock up your entire computer, I do see a couple of reasons for the application to potentially hang...
Your while loop inside of your SSL server will never break unless your client writes '<EOF>' to the stream; which you would have to force it to do. I would likely do something similar to this:
while(( bytesRec = oSSLStream.Read(bytes,0,bytes.Length)) > 0 )
{
// Compare input & break
}
-- The while loop you have now ( without a thread sleep ) will consume all of your systems resources waiting for ... something that may never occur.
In a related issue - I note that your 'DoWork' method launches the listener - but does not start a new thread for this listener. This means that the listener is running inside of your interface thread - which will cause the interface ( and potentially more... ) to hang until the process is completed - which as stated, may never happen.
... Ahem... This last paragraph may be incorrect - you are running an async worker, so I may be incorrect in my second assessment.
Cheers, hope this is helpful.
I've had some hanging problems on Windows 8 that I never saw on Windows 7 (with VS2012). As you experienced it worked fine the first time but only locked up Visual Studio (and not my whole machine) and I had to force quit.
The Visual Studio 2012 Update 4 (which focuses on bug fixes and compatibility) seemed to fix it, although I didn't scientifically test this.
Note: As of 9/1/13 this is only the RC2 version so please check for newer versions, and edit this answer when RTM happens.

Reading message(data) from TCPServer Buffer by using StreamReader.ReadLine() in TCPClient(ReadLine() doesn't return until a disconnection)

I have problem with StreamReader.ReadLine() method.I wrote a C# program, but only TCPclient side. I'm using Hercules program to create a TCPServer. I entered the port number and made a connection. Then I ran my program and clicked to Connect button. then, I had connection with TCPServer.
I have no problem with sending data from TCPClient to Hercules(TCPServer). As you see in the picture, I'm entering the string into "Entered to Send" EditText, then I clicked to Send button and I sent the String.(we can observe the sending data from the Received data part.)
Until here, I have no problem. After sending part, I cannot send data from hercules(TCPServer) to TCPClient. In order to send data, I wrote data into the Send part and clicked the Send button. after that, to see the coming data you should click the Show button .....the problem is right here. I can not read the data from the ReadStream Buffer. I debugged my program and I found the problematic part which is:
private void btnShow_Click(object sender, EventArgs e)
{
try
{
string gelen;
gelen = read_stream.ReadLine();
txtReceive.Text = gelen;
MessageBox.Show(gelen, "you have message from server");
}
catch
{
MessageBox.Show("message could not taken !!!");
}
}
inside the try part the line;
gelen = read_stream.ReadLine();
has problem .ReadLine() is not reading the data from buffer. here is the interesting part, when you send data and click the Show button the program freezes, but if you close the connection from hercules.png by clicking Close button, read_stream.ReadLine(); is taking the data and putting into the Received: EditText.
why it takes the data, after disconnection from TCPServer?
May be the \r\n characters are the problem?
I thought that it is waiting for next character. So, when I disconnected it works because it realizes three is no more character. My question is that:
How can I use read_stream.ReadLine(); to take sending data without disconnection?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Net.Sockets;
using System.IO;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace CSharpVeriDenemesi
{
public partial class Form1 : Form
{
//Burda server da tanımladıklarımızdan farklı olarak TcpClient sınıfı ile serverdan gelen bilgileri alıyoruz
public TcpClient Client;
private NetworkStream network_stream;
private StreamReader read_stream;
private StreamWriter write_stream;
private string local_host = "localhost";
private int port_number = 8001;
public TcpListener listener;
// IPAddress localAddress = IPAddress.Parse("127.0.0.1");
public Form1()//form oluşunca otomatik oluşturulan fonksiyon
{
InitializeComponent();
}
private void btnConnect_Click(object sender, EventArgs e)//CONNECT
{
try
{
Client = new TcpClient(local_host, port_number);//İlk parametre bilgisayar adı ikincisi ise port numarasıdır.
MessageBox.Show("Baglandi");
}
catch
{
MessageBox.Show("Baglanamadi");
return;
}
network_stream = Client.GetStream();
read_stream = new StreamReader(network_stream);
write_stream = new StreamWriter(network_stream);
}
private void btnDisconnect_Click(object sender, EventArgs e)//DISCONNECT
{
txtSend.Text = "Disconnect clicked";
try
{
write_stream.Close();
read_stream.Close();
network_stream.Close();
}
catch
{
MessageBox.Show("Düzgün kapatilamiyor !!!" );
}
}
private void btnReset_Click(object sender, EventArgs e)//send ve receive text.box'larını resetliyor.
{
txtSend.Text = "";
txtReceive.Text = "";
MessageBox.Show("Reset'e basıldı");
}
private void Form1_Load(object sender, EventArgs e)//sayfa ilk açıldığında olcaklar için açılan dosya
{
}
private void btnSend_Click(object sender, EventArgs e)//veriyi server'a gönderiyor
{
try
{
write_stream.WriteLine(txtSend.Text);
write_stream.Flush(); //veriyi gönderiyor
MessageBox.Show("Veri gönderildi");
}
catch {
MessageBox.Show("Veri gönderilmedi !!!");
}
}
private void btnShow_Click(object sender, EventArgs e)
{
try
{
string gelen;
gelen = read_stream.ReadLine();
txtReceive.Text = gelen;
MessageBox.Show(gelen, "you have message from server");
}
catch
{
MessageBox.Show("message could not taken !!!");
}
}
}
}
here is my main.cs I forgot to add it. you can write it and try my project...
note: here is the link for hercules it is portable, you can run it easily [http://www.hw-group.com/products/hercules/index_en.html] 3
If your server side doesn't use Stream.WriteLine("something.."); then you will always have to wait for End of line char (\r or \n or \r\n) at client side when using ReadLine() function.
So the ReadLine() will complete only when connection is closed => your problem.
Your code:
write_stream.WriteLine(txtSend.Text);
write_stream.Flush(); //veriyi gönderiyor
is used at client side, to feedback server, it has no meaning with server sending data.
Try your client side by Reading char by char, or use Read() with BUFFER in specific length.

Categories