TCP guarantees delivery. The problem with your code is that he's suggesting that what's transferred to one challenge Write will be subtracted by one Read challenge on the other side. That's not true. Write doesn't "route the package." He's just writing data to the juket. And Read doesn't read the package. He's reading out of the socate buffer what he's got.If you did two Write calls, you waited, and you made one Read, you'll get both calls out.If you made a call to Write, and the data didn't get there, Read only reads the beginning.Cycle processing builder.Append - unreliable, because your code reads from a local buffer, very quickly (as soon as the data goes online!) and reaches a state. !Stream.DataAvailable somewhere in the middle of the message. In addition, he considers that each result is Read may be converted into Unicode. And it doesn't take any account of the fact that a fragment and a half of the symbol can be found at the end or beginning.Reliable ways to choose: https://ru.stackoverflow.com/a/439729/177221 Not to read directly Stream - Put him in. BinaryReaderand read lengthreader.ReadInt32()Then it's exactly as good a bete as it takes.reader.GetBytes(messageLength) I'll wait until the right number of Byte arrives. Or use it. binaryWriter.Write(message) / binaryReader.ReadString()which automatically does the same for you.Introduce a sign of the end of the message, e.g. the symbol of the portable line. Read as long as there's no relevant bat in the rereaded fragment (and not Stream.DataAvailable) And then accumulate what's in it. MemoryStreamin the form of a white to avoid problems with half a young symbol. At the end, turn the whole message into line.Example on question code (with minimum modifications):Client is simply replacing work from stream to work with reader / writer:using System;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace ChatClient
{
class Program
{
static string userName;
private const string host = "127.0.0.1";
private const int port = 8888;
static TcpClient client;
static BinaryReader reader;
static BinaryWriter writer;
static void Main(string[] args)
{
Console.Write("Введите свое имя: ");
userName = Console.ReadLine();
client = new TcpClient();
try
{
client.Connect(host, port); //подключение клиента
var stream = client.GetStream(); // возвращает объект NetworkStream
reader = new BinaryReader(stream, Encoding.Unicode, true);
writer = new BinaryWriter(stream, Encoding.Unicode, true);
writer.Write(userName);
// запускаем новый поток для получения данных
Thread receiveThread = new Thread(new ThreadStart(ReceiveMessage));
receiveThread.Start(); //старт потока
Console.WriteLine("Добро пожаловать, {0}", userName);
SendMessage();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
Disconnect();
}
}
// отправка сообщений
static void SendMessage()
{
label1: Console.WriteLine("\nВведите сообщение: ");
while (true)
{
string message = Console.ReadLine();
if (message != "exit")
{
writer.Write(message);
}
else
{
message = "exit";
label2: Console.WriteLine("Вы действительно хотите выйти из чата Y / N:");
switch (Console.ReadKey().Key)
{
case ConsoleKey.Y:
writer.Write(message);
Disconnect();
break;
case ConsoleKey.N:
goto label1;
default:
Console.WriteLine("Введите Y / N\n");
goto label2;
}
}
}
}
// получение сообщений
static void ReceiveMessage()
{
while (true)
{
try
{
string message = reader.ReadString();
Console.WriteLine(message);//вывод сообщения
}
catch
{
Console.WriteLine("Подключение прервано!"); //соединение было прервано
Console.ReadLine();
Disconnect();
}
}
}
static void Disconnect()
{
Console.WriteLine("disconect");
if (client != null)
client.Close();//отключение клиента
Environment.Exit(0); //завершение процесса
}
}
}
Sever is the same with the same coding:using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading;
namespace ChatServer
{
public class ServerObject
{
static TcpListener tcpListener; // сервер для прослушивания
List<ClientObject> clients = new List<ClientObject>(); // все подключения
protected internal void AddConnection(ClientObject clientObject)
{
clients.Add(clientObject);
}
protected internal void RemoveConnection(string id)
{
// получаем по id закрытое подключение
ClientObject client = clients.FirstOrDefault(c => c.Id == id);
// и удаляем его из списка подключений
if (client != null)
clients.Remove(client);
}
// прослушивание входящих подключений
protected internal void Listen()
{
try
{
tcpListener = new TcpListener(IPAddress.Any, 8888);
tcpListener.Start();
Console.WriteLine("Сервер запущен. Ожидание подключений...");
while (true)
{
TcpClient tcpClient = tcpListener.AcceptTcpClient(); //Приём ожидающего запроса на подключение
ClientObject clientObject = new ClientObject(tcpClient, this);
Thread clientThread = new Thread(new ThreadStart(clientObject.Process));
clientThread.Start();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Disconnect();
}
}
// трансляция сообщения подключенным клиентам
protected internal void BroadcastMessage(string message, string id)
{
for (int i = 0; i < clients.Count; i++)
{
if (clients[i].Id != id) // если id клиента не равно id отправляющего
{
clients[i].SendMessage(message); //передача данных
}
}
}
// отключение всех клиентов
protected internal void Disconnect()
{
tcpListener.Stop(); //остановка сервера
for (int i = 0; i < clients.Count; i++)
{
clients[i].Close(); //отключение клиента
}
Environment.Exit(0); //завершение процесса
}
}
}
using System;
using System.IO;
using System.Net.Sockets;
using System.Text;
namespace ChatServer
{
public class ClientObject
{
protected internal string Id { get; private set; }
string userName;
TcpClient client;
ServerObject server; // объект сервера
BinaryWriter writer;
public ClientObject(TcpClient tcpClient, ServerObject serverObject)
{
Id = Guid.NewGuid().ToString();
client = tcpClient;
server = serverObject;
serverObject.AddConnection(this);
}
public void Process()
{
try
{
var stream = client.GetStream();
this.writer = new BinaryWriter(stream, Encoding.Unicode, false);
var reader = new BinaryReader(stream, Encoding.Unicode, false);
// получаем имя пользователя
string message = reader.ReadString();
userName = message;
string s = new String('*', 6);
message = userName + " вошел в чат";
// посылаем сообщение о входе в чат всем подключенным пользователям
server.BroadcastMessage(message, this.Id);
Console.WriteLine(message);
// в бесконечном цикле получаем сообщения от клиента
while (true)
{
try
{
message = reader.ReadString();
if (message == "exit")
{
message = String.Format($"{s}{userName}: покинул чат{s}");
Console.Write(message);
server.BroadcastMessage(message, this.Id);
break;
}
else
{
message = String.Format($"{userName}: {message}");
Console.WriteLine(message);
server.BroadcastMessage(message, this.Id);
}
}
catch
{
message = String.Format($"{s}{userName}: покинул чат{s}");
Console.Write(message);
server.BroadcastMessage(message, this.Id);
break;
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
// в случае выхода из цикла закрываем ресурсы
server.RemoveConnection(this.Id);
Close();
}
}
internal void SendMessage(string message)
{
this.writer.Write(message);
}
public void Close()
{
if (client != null)
client.Dispose();
}
}
}