I am learning Socket Programming to make a chat room.
I know that I could use async socket such as
listenFd.BeginAccept(AcceptCallback, listenFd);
Also I could use
Socket.Select(checkRead,null,null,1000);
I know the basic meaning of what async
and select
does.
However, I don't know in what scenario one should be better than the other.
Edit:
Actually I was following a tutorial. It said using select is better than async because the logic is more clear.
Here are two examples:
The one use select:
namespace Server
{
class App
{
static Dictionary<Socket, ClientState> clients = new Dictionary<Socket, ClientState>();
static string ipAddr="127.0.0.1";
static int port=8888;
static void Main(string[] args)
{
Socket listenFd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress iPAddress = IPAddress.Parse(ipAddr);
IPEndPoint iPEndPoint = new IPEndPoint(iPAddress, port);
listenFd.Bind(iPEndPoint);
listenFd.Listen(0);
Console.WriteLine("Server start!");
List<Socket>checkRead=new List<Socket>();
while(true)
{
checkRead.Clear();
checkRead.Add(listenFd);
foreach(var clientState in clients.Values)
{
checkRead.Add(clientState.socket);
}
Socket.Select(checkRead,null,null,1000);
foreach(var socket in checkRead)
{
if(socket==listenFd)
{
ReadListenfd(socket);
}
else
{
ReadClientfd(socket);
}
}
}
}
public static void ReadListenfd(Socket listenfd)
{
Console.WriteLine("Accept");
Socket clientfd=listenfd.Accept();
ClientState state=new ClientState();
state.socket=clientfd;
clients.Add(clientfd,state);
}
public static bool ReadClientfd(Socket clientfd)
{
ClientState state=clients[clientfd];
int count=0;
try
{
count=clientfd.Receive(state.readBuff);
}
catch(SocketException ex)
{
clientfd.Close();
clients.Remove(clientfd);
Console.WriteLine($"Receive Socket Exception {ex.ToString()}");
return false;
}
if(count==0)
{
clientfd.Close();
clients.Remove(clientfd);
Console.WriteLine("Socket close");
return false;
}
string recvStr=System.Text.Encoding.Default.GetString(state.readBuff,0,count);
Console.WriteLine($"Rec {recvStr}");
string strFromClientWithTime= DateTime.Now.ToString("hh:mm")+recvStr;
byte[]sendBytes=System.Text.Encoding.Default.GetBytes(strFromClientWithTime);
foreach(ClientState cs in clients.Values)
{
cs.socket.Send(sendBytes);
}
return true;
}
}
}
The one use Async:
namespace Server
{
class App
{
static Dictionary<Socket, ClientState> clients = new Dictionary<Socket, ClientState>();
static void Main(string[] args)
{
Socket listenFd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress iPAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint iPEndPoint = new IPEndPoint(iPAddress, 8888);
listenFd.Bind(iPEndPoint);
listenFd.Listen(0);
Console.WriteLine("Server start!");
listenFd.BeginAccept(AcceptCallback, listenFd);
while(true)
{
Thread.Sleep(1000);
}
}
static void AcceptCallback(IAsyncResult result)
{
var listenfd = result.AsyncState as Socket;
var connfd = listenfd.EndAccept(result);
var clientState = new ClientState { socket = connfd };
clients.Add(connfd, clientState);
connfd.BeginReceive(clientState.readBuff, 0, 1024, 0, EndReceiveCallback, connfd);
Console.WriteLine($" Client connected!");
listenfd.BeginAccept(AcceptCallback, listenfd);
}
static void EndReceiveCallback(IAsyncResult result)
{
var connfd = result.AsyncState as Socket;
var count = connfd.EndReceive(result);
if (count <= 0)
{
Console.WriteLine("Client disconnected!");
connfd.Close();
return;
}
connfd.BeginReceive(clients[connfd].readBuff, 0, 1024, 0, EndReceiveCallback, connfd);
string strFromClient=System.Text.Encoding.Default.GetString(clients[connfd].readBuff,0,count);
Console.WriteLine($"string from client:{strFromClient}");
string strFromClientWithTime= DateTime.Now.ToString("hh:mm")+strFromClient;
byte[] sendBuff= System.Text.Encoding.Default.GetBytes(strFromClientWithTime,0,strFromClientWithTime.Length);
foreach(var conn in clients.Keys)
{
conn.BeginSend(sendBuff, 0, sendBuff.Length, 0, EndSendCallback, conn);
}
}
static void EndSendCallback(IAsyncResult result)
{
var connfd = result.AsyncState as Socket;
connfd.EndSend(result);
}
}
}
In both examples, the Class ClientState
is
class ClientState
{
public Socket socket;
public byte[] readBuff=new byte[1024];
}
Both examples should work well. But I thought async should be better as Damien_The_Unbeliever said.
However, the author of the tutorial in the second edition prefer using select only telling that the logic is more clear.
I have done hours of research but still confused. Is it just a preference or is there sth I am missing here.