我在C#中编写了一个简单的服务器和客户端代码。一旦客户端连接,服务器将逐个向客户端发送欢迎消息,文件大小和字符串,客户端将显示它。客户端将字符串转换为字符串数组并显示它。之后,客户端将向服务器发送一个id,服务器将显示它。但问题是,客户端没有正确显示。当我在运行服务器后运行客户端程序时,它会显示以下内容,而它应该在一行中显示每条消息。
welcome1.cpp,.jpg,.png
此外,在客户端,我编写的用于显示转换后的字符串数组的行在执行此行之后根本不起作用。好像,代码挂了。我在我的代码中标记了它。我的示例代码如下:
服务器
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Text;
namespace server
{
class Program
{
static void Main(string[] args)
{
// Listen on port 1234.
try
{
TcpListener tcpListener = new TcpListener(IPAddress.Any, 1234);
tcpListener.Start();
byte[] data = new byte[1024];
// Infinite loop to connect to new clients.
while (true)
{
// Accept a TcpClient
TcpClient tcpClient = tcpListener.AcceptTcpClient();
NetworkStream ns = tcpClient.GetStream();
//sending welcome message
string welcome = "welcome";
ns.Write(Encoding.ASCII.GetBytes(welcome), 0, welcome.Length);
ns.Flush();
//sending file size
string fsize = "1";
ns.Write(Encoding.ASCII.GetBytes(fsize), 0, fsize.Length);
ns.Flush();
//sending extensions
string[] extensions = { ".cpp", ".jpg", ".png" };
string str = string.Join(",", extensions);
Console.WriteLine(str);
ns.Write(Encoding.ASCII.GetBytes(str), 0, str.Length);
ns.Flush();
//receiving id
int recv = ns.Read(data, 0, data.Length);
string id = Encoding.ASCII.GetString(data, 0, recv);
Console.WriteLine(id);
}
}
catch (Exception e)
{
Console.Write(e.Message);
}
Console.Read();
}
}
}
客户端:
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Text;
namespace client
{
class Program
{
static void Main(string[] args)
{
try
{
TcpClient tcpClient = new TcpClient("127.0.0.1", 1234);
NetworkStream ns = tcpClient.GetStream();
byte[] data = new byte[1024];
StreamWriter sWriter = new StreamWriter(tcpClient.GetStream());
//receiving welcome message
int recv = ns.Read(data, 0, data.Length);
string message = Encoding.ASCII.GetString(data, 0, recv);
Console.WriteLine(message);
//receive filesize
int recv2 = ns.Read(data, 0, data.Length);
string message2 = Encoding.ASCII.GetString(data, 0, recv2);
Console.WriteLine(message2);
//receiving extensions
int recv1 = ns.Read(data, 0, data.Length);
string message1 = Encoding.ASCII.GetString(data, 0, recv1);
Console.WriteLine(message1);
var array2 = message1.Split(',');
foreach (string s in array2) //from this line the program isn't working
{
Console.WriteLine(s);
}
string input = Console.ReadLine();
ns.Write(Encoding.ASCII.GetBytes(input), 0, input.Length);
ns.Flush();
}
catch (Exception e)
{
Console.Write(e.Message);
}
Console.Read();
}
}
}
代码中有什么问题?
答案 0 :(得分:2)
再次查看您的帖子后,我确信我的评论是实际答案:
代码已挂起int recv2
,因为所有数据都将由第一个ns.read
收到,并且上述行中的第二个调用正在阻止,因为不再存在数据。
您需要添加一个“高级协议”,以便识别每个数据包的数据
样品:
000007welcome
每个消息的开头6个字节(4个就足够了)指定用户数据的长度。因此,您可以轻松地分离看起来像
的数据000007welcome0000011000014.cpp,.jpg,.png
当然,您必须创建用于创建/添加和分离/解释6字节标题的功能(实际上只是一个长度信息,但可以增强以包含多个信息),但这很容易。<登记/> 一般情况下,您应该始终考虑每个操作的时序问题,而不只是添加2个整数:文件访问,通过网络或其他媒体进行数据传输,......实际上是任何类型的硬件访问。因此,通过网络发送数据意味着数据包可以
ns.read
为真时调用ns.DataAvailable
。这意味着,根据数据的重要性,您可能需要针对这些情况采取安全措施
最后你可能想要处理(意外)连接损失......
我还建议您查看我在其他网络问题上的答案,以获取有关调试,测试,常见问题的建议......
答案 1 :(得分:1)
代码:
// Receive the welcome message.
int recv = ns.Read(data, 0, data.Length);
string message = Encoding.ASCII.GetString(data, 0, recv);
Console.WriteLine(message);
// Receive the file size.
int recv2 = ns.Read(data, 0, data.Length);
string message2 = Encoding.ASCII.GetString(data, 0, recv2);
Console.WriteLine(message2);
// Receive the extensions.
int recv1 = ns.Read(data, 0, data.Length);
string message1 = Encoding.ASCII.GetString(data, 0, recv1);
Console.WriteLine(message1);
无效,因为Stream.Read(Byte[], Int32, Int32)
方法具有以下返回值:
返回值
输入:System.Int32
读入缓冲区的总字节数。 如果当前没有多个字节可用,则可以小于请求的字节数;如果已到达流的末尾,则可以为零(0)。
Stream
课程不保证&#34;数据对应&#34;在Stream.Write()
和Stream.Read()
方法调用之间。例如,如果Stream.Write()
方法调用写入6个字节,则第一个Stream.Read()
方法调用可能返回1个字节(第一个字节)。
因为&#34;流媒体&#34;有必要将逻辑消息定义为&#34; extract&#34; (&#34;检测&#34;)来自流的。
需要加入&#34;消息使用&#34;分隔符&#34;发送和&#34;拆分&#34;消息使用&#34;分隔符&#34;收到时可以考虑使用以下替代方案之一来实现&#34;分隔符&#34;概念:
小文章TCP/IP client-server application: exchange with string messages可能有助于理解上述替代方案。