C#System.Net、ソケットNetworkStream.Writeデータが受信ソケットに届かないようです。
私は何が間違っているのか分かりません。
ストーリーは、私はTcpClientソケットから別のTcpClientソケットにbyte []アプリケーションデータを送ります。アプリケーションデータが送信される前にカスタムの疑似Athenticationテストを追加するまでは、すべてうまくいきます。その後、最初に送受信したデータは失敗します。
私は失敗と言っていますが、実際には、読み取りソケットで3バイトがすべて0に設定されているように見えます。
Authenticateメソッドは次の処理を行います。 サーバ側は1バイトのデータ(0〜85)を送信し、クライアントはそれを受け取り、intとして扱い、3倍してバイトをサーバに返送します。サーバはその値をチェックし、別のバイトを1に戻します。
すべてがうまくいくようですが、認証後にcliendによって送信されたデータは受信されないように見えます。ちょうど3バイトを0に設定します。
私はプログラムの生涯にわたってソケットを開いたままにしておきたいので、ソケットを廃棄するので、ストリームを破棄することはできません。
ここに、クライアントとサーバーの両方の完全なコードがあります。私の間違いがあることを願ったり、私が見逃した問題があります。
コードは、意図的に簡潔さのためにエラーチェックを行わず、問題を示すだけの非常に基本的なものです。
両方のAuthenticateメソッドが単にtrueを返す場合、コードは私がそれを期待する方法とまったく同じように動作することに注意してください。
サーバー。
class Program
{
static Random rnd = new Random(Guid.NewGuid().GetHashCode());
static void Main(string[] args)
{
Process p = Process.Start(@"C:\Users\Teddy\Documents\visual studio 2015\code\Readissue\TheClient\bin\Debug\TheClient.exe");
Console.Title = "Server";
TcpListener lis = new TcpListener(
new IPEndPoint(
IPAddress.Any, 4000
));
lis.Start();
TcpClient cli = lis.AcceptTcpClient();
NetworkStream ns = cli.GetStream();
if (Authenticate(cli, ns))
{
Console.WriteLine("Good!");
// This condition is met
}
else
{
Console.WriteLine("Bad!");
Console.ReadLine();
return;
}
// Wait until Carrier class of client
// Sends data
while (!ns.DataAvailable)
{
Thread.Sleep(100);
}
Console.WriteLine("DataAvailable");
byte[] buffer = new byte[2048];
//bytesread is always the value of 3.
int bytesread = ns.Read(buffer, 0, buffer.Length);
string sdata = Encoding.ASCII.GetString(buffer).Substring(0, bytesread);
Console.WriteLine(sdata);
Console.ReadLine();
p.Kill();
p.Close();
}
private static bool Authenticate(TcpClient cli, NetworkStream ns)
{
//return true;
byte[] rcv = new byte[1];
int isnd = rnd.Next(0, 85);
byte[] snd = new byte[1] { (byte)isnd };
//Sends a random number
//and waits for response
ns.Write(snd, 0, snd.Length);
while (!ns.DataAvailable)
{
Thread.Sleep(10);
}
// Expects response to be
// random number x 3
int br = ns.Read(rcv, 0, rcv.Length);
int ircv = rcv[0];
int iok;
if (ircv == (isnd * 3))
{
// Confirm random number x 3
iok = 1;
byte[] bok = new byte[1] { (byte)iok };
ns.Write(bok, 0, snd.Length);
return true;
}
else
{
iok = 0;
byte[] bok = new byte[1] { (byte)iok };
ns.Write(bok, 0, snd.Length);
return false;
}
}
class Carrier
{
public double PointX { get; set; }
public double PointY { get; set; }
public string Comment { get; set; }
public Carrier(byte[] bytes)
{
string[] tmpStrings = Encoding.ASCII.GetString(bytes)
.Split('|');
PointX = Convert.ToDouble(tmpStrings[0]);
PointY = Convert.ToDouble(tmpStrings[1]);
Comment = tmpStrings[2];
}
}
}
クライアント
class Program
{
static void Main(string[] args)
{
Console.Title = "Client";
IPEndPoint EP = new IPEndPoint(
IPAddress.Parse("192.168.1.100"), 4000
);
TcpClient cli = new TcpClient();
cli.Connect(EP);
if (!cli.Connected)
{
Console.WriteLine("Not connected!");
return;
}
Console.WriteLine("Connected!");
NetworkStream ns = cli.GetStream();
if (Authenticate(cli, ns))
{
Console.WriteLine("Good!");
// This condition is met
}
else
{
Console.WriteLine("Bad!");
return;
}
// Send data to server
Carrier carrier = new Carrier();
string stringtosend = carrier.ToString();
byte[] bytestosend = Encoding.ASCII.GetBytes(stringtosend);
ns.Write(bytestosend, 0, bytestosend.Length);
Console.WriteLine("Data sent!");
Console.ReadLine();
}
private static void UseClient(TcpClient cli, NetworkStream ns)
{
Console.WriteLine(ns.CanRead);
}
private static bool Authenticate(TcpClient client, NetworkStream ns)
{
//return true;
byte[] rcv = new byte[1];
while (!ns.DataAvailable)
{
Thread.Sleep(10);
}
int br = ns.Read(rcv, 0, rcv.Length);
int ircv = rcv[0];
int result = ircv * 3;
byte[] snd = BitConverter.GetBytes(result);
ns.Write(snd, 0, snd.Length);
while (!ns.DataAvailable)
{
Thread.Sleep(10);
}
br = ns.Read(rcv, 0, rcv.Length);
int iok = rcv[0];
if (iok == 1)
{
return true;
}
return false;
}
}
class Carrier
{
public double PointX { get; set; }
public double PointY { get; set; }
public string Comment { get; set; }
public Carrier()
{
PointX = 1.00;
PointY = 2.00;
Comment = "A longer comment string";
}
public override string ToString()
{
return PointX.ToString() + "|"
+ PointY.ToString() + "|"
+ Comment;
}
}
メッセージは、1つのメッセージを送信した後で終了します。通常はBLOCKと呼ばれるコードの終了を停止するためにループが必要です。 WAITONEを使用してブロックすることができます。次のWebページのmsdn非同期の例を参照してください。https://msdn.microsoft.com/en-us/library/w89fhyex(v=vs.110).aspx注:msdnの例は、2つのメッセージの後にも終了します。 – jdweng
私はConsole.ReadLine()という印象を受けました。コードは生きていました。 – TEDSON
はいReadlineはブロックされますが、同期メソッドを使用しており、複数のメッセージを処理するループがありません。 – jdweng