Hi Emon,
no, it's not necessary to have two TCP Socket per client. You can use the same socket in both directions like in following demo:
Server:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Server
{
internal class DemoServer
{
public DemoServer()
{
host = Dns.GetHostEntry(Dns.GetHostName());
addr = host.AddressList[0];
ep = new IPEndPoint(addr, 8888);
listener = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
}
private IPHostEntry host;
private IPAddress addr;
private EndPoint ep;
private Socket listener;
private Socket client;
internal void Start()
{
listener.Bind(ep);
listener.Listen(5);
Console.WriteLine("Server listen");
client = listener.Accept();
Console.WriteLine("Socket connection established!");
Task.Run(() =>
{
try
{
while (true)
{
byte[] bufIn = new Byte[1024];
int numByte = client.Receive(bufIn);
Console.WriteLine($"Text received -> {Encoding.ASCII.GetString(bufIn, 0, numByte)} ");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
});
Task.Run(() =>
{
int n = 1;
try
{
while (true)
{
Thread.Sleep(2000);
string msg = $"{n++}. Message from Server: {DateTime.Now:mm.ss.fff} ";
Console.WriteLine("Text sent -> {0} ", msg);
byte[] bufOut = Encoding.ASCII.GetBytes(msg);
client.Send(bufOut);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
});
}
}
}
ViewModel Client:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
namespace WpfApp1
{
class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
sc = SynchronizationContext.Current;
host = Dns.GetHostEntry(Dns.GetHostName());
addr = host.AddressList[0];
ep = new IPEndPoint(addr, 8888);
sender = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
}
SynchronizationContext sc;
private IPHostEntry host;
private IPAddress addr;
private EndPoint ep;
private Socket sender;
public string Input { get; set; }
public ObservableCollection<string> Output { get; set; } = new ObservableCollection<string>();
public ICommand Cmd { get => new RelayCommand(CmdExec, CanCmdExec); }
public void CmdExec(object parameter)
{
switch (parameter.ToString())
{
case "Connect":
Task.Run(() =>
{
try
{
sender.Connect(ep);
OnPropertyChanged(nameof(Cmd));
while (true)
{
byte[] bufIn = new Byte[1024];
int numByte = sender.Receive(bufIn);
string data = Encoding.ASCII.GetString(bufIn, 0, numByte);
sc.Post(new SendOrPostCallback((state) => { Output.Insert(0, state.ToString()); }), data);
}
}
catch (Exception ex)
{
sc.Post(new SendOrPostCallback((state) => { Output.Insert(0, state.ToString()); }), ex.Message);
}
});
break;
case "Send":
int byteSent = sender.Send(Encoding.ASCII.GetBytes(Input));
break;
default:
break;
}
}
public event EventHandler CanExecuteChanged;
public bool CanCmdExec(object parameter)
{
switch (parameter.ToString())
{
case "Send":
return sender.Connected;
default: return true;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propName = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
}