I am trying to connect to a remote server, log in, and then send data to it and receive data from it using a C# forms application. Originally I wrote a console application, which works fine, but I need to use forms. The problem is that my BeginSend
and BeginReceive
methods in the forms application are not working.
I receive a message from the remote server when my socket first connects to it (successfully), and my ConnectionStatusTest
shows I am still connected. But it seems that the connection is then dropped before I can send data to it. The original message from the server displays again (rather than the new message I want to receive), then the SendDataException
and ReceiveDataException
message boxes display, and the ConnectionStatusTest
tells me I'm not connected any more.
Here's my code:
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ServerForm
{
public partial class LoginForm : Form
{
public LoginForm()
{
InitializeComponent();
}
Socket tcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
ProtocolType.Tcp);
public class StateObject
{
public Socket clientSocket = null;
public const int recvBufferSize = 1024;
public byte[] recvbuffer = new byte[recvBufferSize];
public StringBuilder sb = new StringBuilder();
}
private static ManualResetEvent connectionCompleted = new ManualResetEvent(false);
private static ManualResetEvent sendCompleted = new ManualResetEvent(false);
private static ManualResetEvent recvCompleted = new ManualResetEvent(false);
private static String response = String.Empty;
private void LoginForm_Shown(object sender, EventArgs e)
{
try
{
IHostEntry ipHost = Dns.GetHostEntry("*server's web address*");
IPAddress serverIP = ipHost.AddressList[0];
int port = 7500;
IPEndPoint remoteEP = new IPEndPoint(serverIP, port);
tcpSocket.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), tcpSocket);
connectionCompleted.WaitOne();
tcpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
//tcpSocket.IOControl(IOControlCode.KeepAliveValues, inValue, outValue);
AsyncSendReceiveData.ReceiveData(tcpSocket);
AsyncSendReceiveData.recvCompleted.WaitOne();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "LoginForm_Shown Exception");
}
}
private static void ConnectCallback(IAsyncResult ar)
{
try
{
Socket tcpSocket = (Socket)ar.AsyncState;
tcpSocket.EndConnect(ar);
if (tcpSocket.Connected == true)
{
MessageBox.Show(String.Format("Socket connected to server ({0})",
tcpSocket.RemoteEndPoint.ToString()));
}
connectionCompleted.Set();
}
catch (Exception e)
{
MessageBox.Show(e.Message, "ConnectCallback Exception");
}
}
private void passText_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)13)
{
try
{
string usernameString = userText.Text.ToUpper();
string passwordString = passText.Text.ToUpper();
string loginDetails = String.Format("LOGIN {0}:{1}",
usernameString, passwordString);
string data = loginDetails;
AsyncSendReceiveData.SendData(tcpSocket, data);
AsyncSendReceiveData.sendCompleted.WaitOne();
AsyncSendReceiveData.ReceiveData(tcpSocket);
AsyncSendReceiveData.recvCompleted.WaitOne();
ConnectionStatusTest();
string versionString = "VERSION 3";
data = versionString;
AsyncSendReceiveData.SendData(tcpSocket, data);
AsyncSendReceiveData.sendCompleted.WaitOne();
AsyncSendReceiveData.ReceiveData(tcpSocket);
AsyncSendReceiveData.recvCompleted.WaitOne();
}
catch (SocketException ex)
{
MessageBox.Show(ex.Message, "KeyPress Exception");
}
}
}
public class AsyncSendReceiveData
{
public static ManualResetEvent sendCompleted = new ManualResetEvent(false);
public static ManualResetEvent recvCompleted = new ManualResetEvent(false);
public static void ReceiveData(Socket tcpSocket)
{
try
{
StateObject stateobj = new StateObject();
stateobj.clientSocket = tcpSocket;
tcpSocket.BeginReceive(stateobj.recvbuffer, 0,
StateObject.recvBufferSize, 0,
new AsyncCallback(ReceiveCallback), stateobj);
}
catch (SocketException e)
{
MessageBox.Show(e.Message + "\n" + "Exception occurred" +
e.StackTrace.ToString(), "ReceiveData Exception");
}
}
private static void ReceiveCallback(IAsyncResult ar)
{
try
{
StateObject stateobj = (StateObject)ar.AsyncState;
Socket tcpSocket = stateobj.clientSocket;
int bytesRead = tcpSocket.EndReceive(ar);
if (bytesRead > 0) //This if statement seems to cause slow connection.
{
//Adds more data received to sb
stateobj.sb.Append(Encoding.ASCII.GetString(stateobj.recvbuffer,
0, bytesRead));
//Get the rest of the data, if there is any more.
tcpSocket.BeginReceive(stateobj.recvbuffer, 0,
StateObject.recvBufferSize, 0,
new AsyncCallback(ReceiveCallback), stateobj);
}
else
{
if (stateobj.sb.Length > 1)
{
response = stateobj.sb.ToString();
}
recvCompleted.Set();
MessageBox.Show(response);
}
}
catch (Exception e)
{
MessageBox.Show(e.Message, "ReceiveCallback Exception");
}
}
public static void SendData(Socket tcpSocket, String data)
{
try
{
byte[] sendDataBytes = Encoding.ASCII.GetBytes(data);
tcpSocket.BeginSend(sendDataBytes, 0, sendDataBytes.Length,
SocketFlags.None, new AsyncCallback(SendCallback), tcpSocket);
}
catch (SocketException e)
{
MessageBox.Show(e.Message + "\n" + "Exception occurred" +
e.StackTrace.ToString(), "SendData Exception");
}
}
private static void SendCallback(IAsyncResult ar)
{
try
{
Socket tcpSocket = (Socket)ar.AsyncState;
tcpSocket.EndSend(ar);
sendCompleted.Set();
}
catch (Exception e)
{
MessageBox.Show(e.Message, "SendCallback Exception");
}
}
}
public void ConnectionStatusTest()
{
try
{
byte[] tmp = new byte[1];
bool blockingState = tcpSocket.Blocking;
tcpSocket.Blocking = false;
tcpSocket.Send(tmp, 0, 0, SocketFlags.None);
}
catch (SocketException SockEx)
{
if (SockEx.NativeErrorCode.Equals(10035))
MessageBox.Show("Still connected, but the send would block");
else
{
MessageBox.Show(String.Format("Disconnected: error code {0}",
SockEx.NativeErrorCode.ToString()));
}
}
finally
{
bool blockingState = tcpSocket.Blocking;
}
MessageBox.Show(String.Format("Connected: {0}",
tcpSocket.Connected.ToString()));
I've spent a lot of time trying to work out why the BeginSend and BeginReceive methods aren't working, and I think I've narrowed it down to one of two things:
In the
passText_KeyPress
function, thedata
part ofstring data = loginDetails
is not passed as a parameter to theSendData
function. Therefore theSendData
function doesn't work properly and theSendDataException
is displayed. If this is the problem, how do I passloginDetails
(or some other string) to theSendData
function?When connecting using a console application, I have no problem connecting, logging in, or sending or receiving data, and the connection doesn't get dropped. However, when I tried to connect using telnet, a message came back from the server after about 30 seconds of inactivity, saying "connection to host lost". The connection seems to be dropped after about 30 seconds in my forms application too, and for some reason the form application takes about 25 seconds to tell me I'm connected. I have tried using KeepAlive in the forms application, but apparently the default TCP KeepAlive period is 2 hours. If this is the problem, how could I change this to, say, 20 seconds? Everything I've read suggests either letting Visual Studio through my firewall (I tried this - no luck), or having to change registry keys, which seems a bit too involved as a solution.
The error message is "an established connection was aborted by the software in your host machine", and the error code is 10053, which makes me think I'm getting timed out somehow. I may of course be wrong, and the problem could be something else I haven't spotted. I would really appreciate your help! Thanks.
UPDATE - I've rewritten the code using synchronous methods (and added a timer, just so I can see if I'm still connected every 5 seconds). I now get two different errors.
The first says "A non-blocking socket operation could not be completed immediately" and produces error code 10035. This error occurs at the Receive
method while I am still connected to the remote server. I thought clearing the buffer might help, but it just means I get a blank message the next time I try to read it. So I can only think I'm not actually receiving a new message from the server, even though I know I should be.
The second is the original error - "An established connection was aborted by the software in your host machine", error code 10053 - and this occurs at the Send
method when I get disconnected after 30 seconds. I've read in various places that changing the Socket.Blocking
property might help, but I've tried making it true
and false
just before the calls to the Receive
method, and neither helps.
Any ideas on how I can get this to work?
Revised code:
namespace ServerForm
{
public partial class LoginForm : Form
{
public LoginForm()
{
InitializeComponent();
}
Socket tcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
ProtocolType.Tcp);
byte[] rcvdBytes = new byte [1024];
System.Timers.Timer timer1 = new System.Timers.Timer(5000);
private void LoginForm_Shown(object sender, EventArgs e)
{
try
{
timer1.Enabled = true;
timer1.Elapsed += new ElapsedEventHandler(OnTimedEvent);
timer1.AutoReset = true;
IPHostEntry ipHost = Dns.GetHostEntry("*server's web address*");
IPAddress serverIP = ipHost.AddressList[0];
int port = 7500;
IPEndPoint remoteEP = new IPEndPoint(serverIP, port);
tcpSocket.Connect(remoteEP);
tcpSocket.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.KeepAlive, true); //Has no effect, as I get
//disconnected after 30 seconds.
if (tcpSocket.Connected == true)
{
MessageBox.Show(String.Format("Socket connected to primary
server {0}", tcpSocket.RemoteEndPoint.ToString()));
}
int bytesRcvd = tcpSocket.Receive(rcvdBytes);
MessageBox.Show(String.Format("Response received: {0}",
Encoding.ASCII.GetString(rcvdBytes, 0, rcvdBytes.Length),
"Connected to server"));
Array.Clear(rcvdBytes, 0, rcvdBytes.Length);
}
catch (Exception ex)
{
MessageBox.Show(String.Format(ex.Message, "LoginForm_Shown Exception"));
}
}
private void passText_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)13)
{
try
{
string usernameString = userText.Text.ToUpper();
string passwordString = passText.Text.ToUpper();
string loginDetails = String.Format("LOGIN {0}:{1}",
usernameString, passwordString);
byte[] loginBytes = Encoding.ASCII.GetBytes(loginDetails);
tcpSocket.Send(loginBytes); //SocketException (0x80004005):
//"An established connection was aborted
//by the software in your host machine"
//occurs here once disconnected. Error code 10053
int bytesRcvd = tcpSocket.Receive(rcvdBytes); //SocketException
//(0x80004005): "A non-blocking socket operation could not be
//completed immediately" occurs here while connected.
//Error code 10035
MessageBox.Show(String.Format("Response received: {0}",
Encoding.ASCII.GetString(rcvdBytes, 0, rcvdBytes.Length)));
//Displays same welcome message from server, or nothing if
//I clear the rcvdBytes buffer first, and not a new message.
string versionString = "VERSION 3";
byte[] versionBytes = Encoding.ASCII.GetBytes(versionString);
tcpSocket.Send(versionBytes);
bytesRcvd = tcpSocket.Receive(rcvdBytes);
MessageBox.Show(String.Format("Response received: {0}",
Encoding.ASCII.GetString(rcvdBytes, 0, rcvdBytes.Length)));
ConnectionStatusTest();
}
catch (SocketException sockEx)
{
MessageBox.Show(String.Format("SocketException: {0}",
sockEx.ToString()));
}
catch (ArgumentNullException argNullEx)
{
MessageBox.Show(String.Format("ArgumentNullException: {0}",
argNullEx.ToString()));
}
catch (Exception ex)
{
MessageBox.Show(String.Format("Exception: {0}", ex.ToString()));
}
}
}
public void ConnectionStatusTest()
{
try
{
byte[] tmp = new byte[1];
bool blockingState = tcpSocket.Blocking;
tcpSocket.Blocking = false;
tcpSocket.Send(tmp, 0, 0, SocketFlags.None);
}
catch (SocketException SockEx)
{
if (SockEx.NativeErrorCode.Equals(10035))
MessageBox.Show("Still connected, but the send would block");
else
{
MessageBox.Show(String.Format("Disconnected: error code {0}",
SockEx.NativeErrorCode.ToString()));
}
}
finally
{
bool blockingState = tcpSocket.Blocking;
}
MessageBox.Show(String.Format("Connected: {0}",
tcpSocket.Connected.ToString()));
}
private void LoginForm_FormClosed(object sender, FormClosedEventArgs e)
{
tcpSocket.Shutdown(SocketShutdown.Both);
tcpSocket.Close();
Form1 Childform1 = new Form1();
Childform1.MdiParent = ParentForm;
Childform1.Show();
}
private void OnTimedEvent(object sender, EventArgs e)
{
ConnectionStatusTest();
}
}