リモート サーバーに接続してログインし、C# フォーム アプリケーションを使用してデータを送信し、そこからデータを受信しようとしています。もともと私は正常に動作するコンソール アプリケーションを作成しましたが、フォームを使用する必要があります。問題は、フォーム アプリケーションのmy メソッドBeginSend
とメソッドが機能していないことです。BeginReceive
ソケットが最初にリモート サーバーに接続されたときに (正常に)、リモート サーバーからメッセージを受信しましたが、ConnectionStatusTest
ショーはまだ接続されています。しかし、データを送信する前に接続が切断されたようです。サーバーからの元のメッセージが (受信したい新しいメッセージではなく) 再び表示され、SendDataException
メッセージReceiveDataException
ボックスと が表示され、ConnectionStatusTest
接続されていないことが通知されます。
これが私のコードです:
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()));
BeginSend メソッドと BeginReceive メソッドが機能しない理由を解明するために多くの時間を費やしましたが、次の 2 つのうちの 1 つに絞り込んだと思います。
passText_KeyPress
関数では、 の部分data
がstring data = loginDetails
パラメーターとして関数に渡されませんSendData
。そのため、SendData
機能が正常に動作せず、SendDataException
が表示されます。loginDetails
これが問題である場合、関数に (または他の文字列を)渡すにはどうすればよいSendData
ですか?コンソール アプリケーションを使用して接続する場合、接続、ログイン、データの送受信に問題はなく、接続が切断されることもありません。しかし、telnet を使用して接続しようとすると、約 30 秒間非アクティブになった後、サーバーから「ホストへの接続が失われました」というメッセージが返されました。フォーム アプリケーションでも約 30 秒後に接続が切断されたように見えます。何らかの理由で、フォーム アプリケーションが接続されたことを通知するのに約 25 秒かかります。フォーム アプリケーションで KeepAlive を使用してみましたが、どうやらデフォルトの TCP キープアライブ期間は 2 時間です。これが問題である場合、これをたとえば 20 秒に変更するにはどうすればよいでしょうか? 私が読んだことはすべて、Visual Studioにファイアウォールを通過させるか(これを試しました-運が悪い)、レジストリキーを変更する必要があることを示唆しています。
エラー メッセージは「確立された接続がホスト マシンのソフトウェアによって中止されました」で、エラー コードは 10053 で、何らかの理由でタイムアウトになっていると思われます。もちろん、私は間違っているかもしれませんし、問題は私が見つけていない別の何かかもしれません。助けていただければ幸いです。ありがとう。
更新- 同期メソッドを使用してコードを書き直しました (5 秒ごとにまだ接続されているかどうかを確認できるように、タイマーを追加しました)。現在、2 つの異なるエラーが発生しています。
1 つ目は、「ノンブロッキング ソケット操作をすぐに完了できませんでした」と表示され、エラー コード 10035が生成されます。このエラーはReceive
、リモート サーバーに接続しているときにメソッドで発生します。バッファをクリアすると役立つかもしれないと思ったのですが、次に読もうとしたときに空白のメッセージが表示されるだけです。そのため、サーバーから実際に新しいメッセージを受信しているとはわかっていても、実際には受信していないとしか思えません。
2 番目は元のエラーです - 「ホスト マシンのソフトウェアによって、確立された接続が中止されました」、エラー コード 10053 - これは、Send
メソッドで 30 秒後に切断されたときに発生します。プロパティを変更すると役立つ可能性があることをさまざまな場所で読みましたが、メソッドの呼び出しの直前にそれをSocket.Blocking
作成しようとしましたが、どちらも役に立ちません。true
false
Receive
これを機能させる方法についてのアイデアはありますか?
改訂されたコード:
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();
}
}