System.NullReferenceException: Ссылка на объект не указывает на экземпляр объекта - С#
делаю небольшой месенджер на C#, для изучения net.sockets; Сделал так, чтобы принимание сообщений было ассинхронным, и во время их получения можно было что-то писать.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2
{
class Program
{
//static byte[] buffer = new byte[1024];
static string str;
static Socket client;
static Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
static void Main(string[] args)
{
socket.Bind(new IPEndPoint(IPAddress.Any, 25565));
socket.Listen(5);
Socket client = socket.Accept();
Console.WriteLine("New User!!!");
while (true)
{
MainAsync();
TakeMessage();
}
}
private static async Task TakeMessage() {
byte[] buffer = new byte[1024];
Task.Run(() => client.Receive(buffer)); //Тут ошибка
Task.Run(() => Console.WriteLine(Encoding.ASCII.GetString(buffer)));
}
private static async Task MainAsync()
{
Task.Run(() => str = Console.ReadLine());
Task.Run(()=> command(str));
}
private static async Task NewUser()
{
//Task.Run(()=>)
}
private static void command(string com){
if(com == "close")
{
client.Shutdown(SocketShutdown.Both);
}
}
}
}
Но в 32ой строке появляется ошибка "System.NullReferenceException: "Ссылка на объект не указывает на экземпляр объекта." "
Ответы (1 шт):
У вас не присвоена переменная client. Как я понял, вам нужно 2 сокета, один для отправки сообщений, второй для приема. Так вот, один вы инициализировали, а второй нет. (Кстати, а точно нужно два?)
В то же время Microsoft рекомендует здесь:
Если вы создаете относительно простое приложение, не требующее максимальной производительности, рассмотрите возможность использования
TcpClient,TcpListenerиUdpClient. Эти классы предоставляют более простой и удобный интерфейс для взаимодействия сSocket.
Но это только часть беды. Вы странно используете асинхронность, которая вам не особо и нужна. Вам базово нужно просто 2 потока, один на прием сообщиний, второй на передачу, и чтобы они работали одновременно.
Я написал короткий пример, убрав весь сетевой код, и оставил только скелет для демонстрации шаблона с двумя одновременно работающими задачами.
Для управления прерыванием задач я буду использовать CancellationToken. Изучите его, он много где может пригодиться. Его так же можно передавать в разного рода стандартные асинхронные методы.
// асинхронный Main, обратите внимание
static async Task Main(string[] args)
{
using (CancellationTokenSource cts = new CancellationTokenSource())
{
List<Task> loops = new List<Task>();
loops.Add(Task.Run(() => ReceiveMessageLoop(cts)));
loops.Add(Task.Run(() => SendMessageLoop(cts)));
await Task.WhenAll(loops);
}
Console.WriteLine("Shutdown");
Console.ReadKey();
}
private static void ReceiveMessageLoop(CancellationTokenSource cts)
{
while (true)
{
Console.WriteLine("ReceiveMessageLoop");
Thread.Sleep(5000);
if (cts.Token.IsCancellationRequested)
{
break;
}
}
Console.WriteLine("ReceiveMessageLoop exit");
}
private static void SendMessageLoop(CancellationTokenSource cts)
{
while (true)
{
Console.Write("Command: ");
string command = Console.ReadLine();
if (command == "exit")
{
cts.Cancel();
}
if (cts.Token.IsCancellationRequested)
{
break;
}
}
Console.WriteLine("SendMessageLoop exit");
}
А вот доказательство, что асинхронность не особо и нужна, разницы в поведении приложения не будет.
// обычный синхронный Main
static void Main(string[] args)
{
using (CancellationTokenSource cts = new CancellationTokenSource())
{
List<Task> loops = new List<Task>();
loops.Add(Task.Run(() => ReceiveMessageLoop(cts)));
loops.Add(Task.Run(() => SendMessageLoop(cts)));
Task.WaitAll(loops.ToArray());
}
Console.WriteLine("Shutdown");
Console.ReadKey();
}
А по реализации сетевой части с помощью Socket, если вам уж так очень хочется, да еще и с асинхронностью, смотрите примеры в документации: Client, Server.
Еще на заметку: async без await внутри ни имеет никакого смысла и не дает никакого эффекта, а обратное вообще невозможно. :)