【发布时间】:2020-06-13 11:18:48
【问题描述】:
我需要通过 TCP 实现 HTTP 协议。我已经有了一个运行良好的 TCP/IP 客户端-服务器程序。
现在,我对源代码做了一些小的改动,使它的行为类似于an HTTP client-server。但是,不幸的是它停止了工作。
以下代码...
public void Write(string str)
{
if (IsConnected)
{
byte[] strBytes = Encoding.UTF8.GetBytes(str);
byte[] lenBytes = BitConverter.GetBytes(strBytes.Length);
Array.Reverse(lenBytes);
writer.Write(lenBytes);
writer.Write(strBytes);
writer.Flush();
}
else
{
throw new Exception("Client " + ID + " is not connected!");
}
}
public string Read()
{
if (IsConnected)
{
byte[] lenBytes = reader.ReadBytes(4);
Array.Reverse(lenBytes);
int len = BitConverter.ToInt32(lenBytes, 0);
byte[] bytes = reader.ReadBytes(len);
string str = Encoding.UTF8.GetString(bytes);
return str;
}
else
{
throw new Exception("Client " + ID + " is not connected!");
}
}
改为:
public void Write(string str)
{
if (IsConnected)
{
byte[] send = Encoding.ASCII.GetBytes(str);
writer.Write(send);
writer.Flush();
}
else
{
throw new Exception("Client " + ID + " is not connected!");
}
}
public string Read()
{
if (IsConnected)
{
StreamReader sr = new StreamReader(stream);
string str = sr.ReadToEnd();
return str;
}
else
{
throw new Exception("Client " + ID + " is not connected!");
}
}
这里有什么问题?
详细的源代码
服务器程序和客户端程序都使用以下类。
修改:
namespace MyClientServer
{
public class ClientClass
{
private string Host { get; set; }
private int Port { get; set; }
private bool IsConnected = false;
public string ID { get; private set; }
public TcpClient Tcp { get; private set; }
NetworkStream stream;
private StreamReader sr;
private StreamWriter writer;
public ClientClass()
{
Random rnd = new Random();
ID = AlphaNumRandom.GenerateUpperCaseString(5, rnd);
}
//constructor for server program.
public ClientClass(TcpListener listener)
{
Tcp = listener.AcceptTcpClient();
Host = ((IPEndPoint)Tcp.Client.RemoteEndPoint).Address.ToString();
Port = ((IPEndPoint)Tcp.Client.LocalEndPoint).Port;
IsConnected = true;
stream = Tcp.GetStream();
sr = new StreamReader(stream);
writer = new StreamWriter(stream);
ID = Read();
Console.WriteLine("Client [{0}] is now connected.", ID);
}
public bool Connect()
{
if (IsConnected == false)
{
Console.WriteLine("Client [{0}] is now connected.", ID);
IsConnected = true;
Tcp = new TcpClient(Host, Port);
stream = Tcp.GetStream();
sr = new StreamReader(stream);
writer = new StreamWriter(stream);
return true;
}
return false;
}
//constructor for client.
public ClientClass(string host, int port)
{
Random rnd = new Random();
ID = AlphaNumRandom.GenerateUpperCaseString(5, rnd);
Host = host;
Port = port;
}
public void Write(string str)
{
if (IsConnected)
{
byte[] send = Encoding.ASCII.GetBytes(str);
writer.Write(send);
writer.Flush();
}
else
{
throw new Exception("Client " + ID + " is not connected!");
}
}
public string Read()
{
if (IsConnected)
{
StreamReader sr = new StreamReader(stream);
string str = sr.ReadToEnd();
return str;
}
else
{
throw new Exception("Client " + ID + " is not connected!");
}
}
public void PrintID()
{
Console.WriteLine("Client ID = {0}", ID);
}
public void SendIdToServer()
{
this.Write(ID);
}
public bool Disconnect()
{
if (IsConnected)
{
if (Tcp != null)
{
Tcp.Close();
Tcp = null;
Console.WriteLine("\nClient [{0}] is now disconnected.", ID);
return true;
}
}
return false;
}
}
}
原文:
namespace MyClientServer
{
public class ClientClass
{
private string Host { get; set; }
private int Port { get; set; }
private bool IsConnected = false;
public string ID { get; private set; }
public TcpClient Tcp { get; private set; }
private BinaryReader reader;
private BinaryWriter writer;
public ClientClass()
{
Random rnd = new Random();
ID = AlphaNumRandom.GenerateUpperCaseString(5, rnd);
}
//constructor for server program.
public ClientClass(TcpListener listener)
{
Tcp = listener.AcceptTcpClient();
Host = ((IPEndPoint)Tcp.Client.RemoteEndPoint).Address.ToString();
Port = ((IPEndPoint)Tcp.Client.LocalEndPoint).Port;
IsConnected = true;
NetworkStream stream = Tcp.GetStream();
reader = new BinaryReader(stream);
writer = new BinaryWriter(stream);
ID = Read();
Console.WriteLine("Client [{0}] is now connected.", ID);
}
public bool Connect()
{
if (IsConnected == false)
{
Console.WriteLine("Client [{0}] is now connected.", ID);
IsConnected = true;
Tcp = new TcpClient(Host, Port);
NetworkStream stream = Tcp.GetStream();
reader = new BinaryReader(stream);
writer = new BinaryWriter(stream);
return true;
}
return false;
}
//constructor for client.
public ClientClass(string host, int port)
{
Random rnd = new Random();
ID = AlphaNumRandom.GenerateUpperCaseString(5, rnd);
Host = host;
Port = port;
}
public void Write(string str)
{
if (IsConnected)
{
byte[] strBytes = Encoding.UTF8.GetBytes(str);
byte[] lenBytes = BitConverter.GetBytes(strBytes.Length);
Array.Reverse(lenBytes);
writer.Write(lenBytes);
writer.Write(strBytes);
writer.Flush();
}
else
{
throw new Exception("Client " + ID + " is not connected!");
}
}
public string Read()
{
if (IsConnected)
{
byte[] lenBytes = reader.ReadBytes(4);
Array.Reverse(lenBytes);
int len = BitConverter.ToInt32(lenBytes, 0);
byte[] bytes = reader.ReadBytes(len);
string str = Encoding.UTF8.GetString(bytes);
return str;
}
else
{
throw new Exception("Client " + ID + " is not connected!");
}
}
public void PrintID()
{
Console.WriteLine("Client ID = {0}", ID);
}
public void SendIdToServer()
{
this.Write(ID);
}
public bool Disconnect()
{
if (IsConnected)
{
if (Tcp != null)
{
Tcp.Close();
Tcp = null;
Console.WriteLine("\nClient [{0}] is now disconnected.", ID);
return true;
}
}
return false;
}
}
}
【问题讨论】:
-
Windows 中的流在关闭之前不会结束。当它用于读取文件时,Windows 将关闭流。当一个流用于连接两个进程时,一个进程需要关闭流。当流与 TCP 一起使用时,流在连接关闭时关闭。
-
为什么是
Encoding.ASCII.GetBytes(str)? ASCII 编码器能理解这里所有的字符串内容吗?阅读器还将 StreamReader 初始化为StreamReader sr = new StreamReader(stream);,它假定 UTF8 编码(NO-BOM,因此不检查。)。 -
@Jimi, Why
Encoding.ASCII.GetBytes(str)? --- 因为,HTTP 使用简单的文本,,,,, 读者还初始化了StreamReader as StreamReader sr = new StreamReader(stream);,它假定 UTF8 编码(NO-BOM,因此它不检查。)。 --- UTF8 在新代码中完全删除。 -
不,您在新代码中有
StreamReader sr = new StreamReader(stream);。 StreamReader 假设 Stream 是 UTF-8 编码的。如果所有字符都被限制在 ASCII 表中,那么读者和作者两者可以交谈。如果是这种情况,那么在 StreamReader 构造函数中指定 ASCII 编码(我没有阅读所有其余部分 - 这是我书中的游戏终结者)。我不知道什么是简单文本。您通过 HTTP 连接发送字节。
标签: c# http tcpclient tcplistener