I'm making a communication via a socket but I'm having problems sending data from the server.
I'm able to send a response after receiving something but I need to be able to send a message without receiving anything from the client beforehand.
What I want to do is basically send a command over the socket after a connection is established. (after AcceptCallback() was called, which I check for). In my main program I have a button which I want to be able to click anytime to send a certain message. However, every time I try this I get an error that I cannot anything over an unconnected socket.
As you can see in the code I tried to send another message after receiving something from my client (see in the ReceiveCallback() where I send "Test send"). Sending that works, but if I want to send something else afterwards it again gives the error that I can't send something over a disconnected socket.
The current code looks like this(excerpts):
class SocketServer
{
private static Socket _serverSocket;
//Konstruktor
public SocketServer(int port = 9851)
{
_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //Socket Objekt
lep = new IPEndPoint(IPAddress.Any, 9851);
}
private static void AcceptClient()
{
try
{
_serverSocket.Bind(lep);
_serverSocket.Listen(100);
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket); //auf Verbindungen warten weiter bei AcceptCallback Methode
}
catch
{
...
}
}
private static void AcceptCallback(IAsyncResult AR) //Connection accept callback
{
try
{
Socket socket = _serverSocket.EndAccept(AR);
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket);
}
catch (ObjectDisposedException e)
{
...
}
}
private static void ReceiveCallback(IAsyncResult AR)//Weiterführung Empfangen
{
Socket socket = (Socket)AR.AsyncState;
try
{
received = socket.EndReceive(AR); //Speichere Anzahl empfangener Bytes
... //trimming and saving the received data in a string
sending = "Test send";
byte[] data = Encoding.UTF8.GetBytes(sending);
socket.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket);
}
catch (ObjectDisposedException e)
{
...
}
}
public void SendMessage()
{
byte[] data = Encoding.UTF8.GetBytes(sending);
_serverSocket.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(SendCallback), _serverSocket); //Beginnen des Sendevorgangs weiter bei SendCallback
...
}
private static void SendCallback(IAsyncResult AR)
{
Socket socket = (Socket)AR.AsyncState;
socket.EndSend(AR);
...
}
I've been working on this problem for over a week now. It's kind of hard to say what I tried before because I feel like I've tried everything and looked in the deepest part of the internet for help. So I'm standing before that possibilities that a)I am super blind somewhere, b) I'm overworked or c) it's actually impossible, sorry Rhino you need to scrap your project and start anew.
Anyway I'd be grateful for any kind of help. Thanks.
This is how I solved my problems:
The Problem was that I didn't use BeginSend(...) on the socket connection that I had used with EndAccept(), which was just named socket.
To be able to use this specific socket in any other method and not just the AcceptCallback(), I had to make it accessible.
I created a List to save Accepted sockets in called _clientSockets to which I added every accepted socket.
It now looks like this (only the parts that changed):
class SocketServer
{
private static Socket _serverSocket;
private static List<Sockets> _clientSockets=new List<Socket>();
private static void AcceptClient()
{
try
{
_serverSocket.Bind(lep);
_serverSocket.Listen(100);
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket); //auf Verbindungen warten weiter bei AcceptCallback Methode
}
catch
{
...
}
}
private static void AcceptCallback(IAsyncResult AR) //Connection accept callback
{
try
{
Socket socket = _serverSocket.EndAccept(AR);
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), _serverSocket);
_clientSockets.Add(socket); //This is the important part where I add the completed socket connection to the list!
}
catch
{
...
}
}
public void SendMessage(string sdata, int socketno)
{
Socket socket = _clientSockets[socketno] //Here I give the socket from before, or whichever one I choose, to this method to proceed with
byte[] data = Encoding.UTF8.GetBytes(sdata);
socket.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket); //Beginnen des Sendevorgangs weiter bei SendCallback
...
}
private static void SendCallback(IAsyncResult AR)
{
Socket socket = (Socket)AR.AsyncState;
socket.EndSend(AR);
...
}
Related
Trying to learn Test Driven Design for the first time. I have a server that goes like this:
public class ServerEngine
{
private static Socket _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private static List<Socket> _clientSockets = new List<Socket>();
private static byte[] _buffer = new byte[1024];
public ServerEngine()
{
SetupServer();
}
private void SetupServer()
{
Console.WriteLine("Setting up the server...");
_serverSocket.Bind(new IPEndPoint(IPAddress.Any, 100));
// Settingup the backlog
_serverSocket.Listen(1);
//Listen for connections
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
private void AcceptCallback(IAsyncResult ar)
{
// Add the accepted socket to the list of sockets
Socket socket = _serverSocket.EndAccept(ar);
_clientSockets.Add(socket);
Console.WriteLine("A client has connected");
// listen for messages coming from the new accepted socket
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
// Start accepting a new connection again
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
private void ReceiveCallback(IAsyncResult ar)
{
Socket socket = (Socket)ar.AsyncState;
try
{
var received = socket.EndReceive(ar);
var dataBuf = new byte[received];
Array.Copy(_buffer, dataBuf, received);
var text = Encoding.ASCII.GetString(dataBuf);
Console.WriteLine($"Text Received: {text}");
var response = AddToHashSet(text);
var data = Encoding.ASCII.GetBytes(response.ToString());
socket.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket);
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
catch (SocketException)
{
socket.Close();
Console.WriteLine("A client has disconnected.");
}
}
private void SendCallback(IAsyncResult ar)
{
Socket socket = (Socket)ar.AsyncState;
socket.EndSend(ar);
}
private HashSet<TidContainerModel> _tidContainerModels = new HashSet<TidContainerModel>(new TidContainerModelComparer());
private bool AddToHashSet(string value)
{
var tcv = new TidContainerModel
{
Tid = value,
TimeAdded = DateTime.Now,
Type = 'R',
Rssi = -444
};
return _tidContainerModels.Add(tcv);
}
}
This I call in the Program Main to setup the server. Then I created an xUnit test like so:
private Socket _clentSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private ServerEngine serverEngine = new ServerEngine();
[Fact]
public void ConnectToServerTest()
{
// Arrange
bool expected = true;
// Act
bool actual = LoopConnect();
// Assert
Assert.Equal(expected, actual);
}
private bool LoopConnect()
{
int attempts = 0;
var connected = false;
while (!_clentSocket.Connected)
{
try
{
attempts++;
var ipAddress = new IPEndPoint(IPAddress.Parse("172.16.35.71"), 100);
_clentSocket.Connect(ipAddress);
}
catch (SocketException se)
{
Console.Clear();
Console.WriteLine($"Failed connecting {se.Message}. Reconnecting attempt {attempts}");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
connected = true;
Console.Clear();
Console.WriteLine("Connected to the server");
return connected;
}
Without using the Test this program runs fine. But when I use the test, I fail with an error of:
Server.Test.ServerEngineTest.ConnectToServerTest
Source: ServerEngineTest.cs line 15
Duration: 209 ms
Message:
System.IO.IOException : The handle is invalid.
Stack Trace:
__Error.WinIOError(Int32 errorCode, String maybeFullPath)
Console.GetBufferInfo(Boolean throwOnNoConsole, Boolean& succeeded)
Console.Clear()
ServerEngineTest.LoopConnect() line 51
ServerEngineTest.ConnectToServerTest() line 21
If I use a console application to connect to the server, it works perfect. I want to learn how to use the xUnit with this project.
Look at your stack trace, it's telling you the problem:
Stack Trace:
__Error.WinIOError(Int32 errorCode, String maybeFullPath)
Console.GetBufferInfo(Boolean throwOnNoConsole, Boolean& succeeded)
Console.Clear()
ServerEngineTest.LoopConnect() line 51
ServerEngineTest.ConnectToServerTest() line 21
Basically, you're trying to clear the console, but you have no console allocated in your test. Which is something you should never do for two reasons:
You should be mocking your I/O to be able to test it.
You should absolutely never mix this kind of console I/O with your socket service, whatever it does. Use dependency injection to extract and contain console I/O (or even better, a proper logging interface) separate from the actual work of starting and maintaining a TCP server.
I've been looking at many tcp client/server examples and would want to know how one can go about creating a method to identify each client. One way I know is through lets say, a log in authentication. I know how to connect, and query a database, but how would I lets say after successful authentication, take the username and say this username is this socket. A class example or simple method would be appreciated as an example. I want to be able to target all connected clients by their username from a database individually.
Example I'm using for server
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace MultiServer
{
class Program
{
private static readonly Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private static readonly List<Socket> clientSockets = new List<Socket>();
private const int BUFFER_SIZE = 2048;
private const int PORT = 100;
private static readonly byte[] buffer = new byte[BUFFER_SIZE];
static void Main()
{
Console.Title = "Server";
SetupServer();
Console.ReadLine(); // When we press enter close everything
CloseAllSockets();
}
private static void SetupServer()
{
Console.WriteLine("Setting up server...");
serverSocket.Bind(new IPEndPoint(IPAddress.Any, PORT));
serverSocket.Listen(0);
serverSocket.BeginAccept(AcceptCallback, null);
Console.WriteLine("Server setup complete");
}
/// <summary>
/// Close all connected client (we do not need to shutdown the server socket as its connections
/// are already closed with the clients).
/// </summary>
private static void CloseAllSockets()
{
foreach (Socket socket in clientSockets)
{
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
serverSocket.Close();
}
private static void AcceptCallback(IAsyncResult AR)
{
Socket socket;
try
{
socket = serverSocket.EndAccept(AR);
}
catch (ObjectDisposedException) // I cannot seem to avoid this (on exit when properly closing sockets)
{
return;
}
clientSockets.Add(socket);
socket.BeginReceive(buffer, 0, BUFFER_SIZE, SocketFlags.None, ReceiveCallback, socket);
Console.WriteLine("Client connected, waiting for request...");
serverSocket.BeginAccept(AcceptCallback, null);
}
private static void ReceiveCallback(IAsyncResult AR)
{
Socket current = (Socket)AR.AsyncState;
int received;
try
{
received = current.EndReceive(AR);
}
catch (SocketException)
{
Console.WriteLine("Client forcefully disconnected");
// Don't shutdown because the socket may be disposed and its disconnected anyway.
current.Close();
clientSockets.Remove(current);
return;
}
byte[] recBuf = new byte[received];
Array.Copy(buffer, recBuf, received);
string text = Encoding.ASCII.GetString(recBuf);
Console.WriteLine("Received Text: " + text);
if (text.ToLower() == "get time") // Client requested time
{
Console.WriteLine("Text is a get time request");
byte[] data = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString());
current.Send(data);
Console.WriteLine("Time sent to client");
}
else if (text.ToLower() == "exit") // Client wants to exit gracefully
{
// Always Shutdown before closing
current.Shutdown(SocketShutdown.Both);
current.Close();
clientSockets.Remove(current);
Console.WriteLine("Client disconnected");
return;
}
else
{
Console.WriteLine("Text is an invalid request");
byte[] data = Encoding.ASCII.GetBytes("Invalid request");
current.Send(data);
Console.WriteLine("Warning Sent");
}
current.BeginReceive(buffer, 0, BUFFER_SIZE, SocketFlags.None, ReceiveCallback, current);
}
}
}
There's a very simple solution to that when you're using the asynchronous callbacks (though I'd strongly recommend switching to a newer approach, or even better, an existing library - raw TCP is hard to do right).
The callback delegate can point to an instance method. This means you can have something like this:
class Client
{
private readonly Socket socket;
public readonly byte[] ReceiveBuffer = new byte[BUFFFER_SIZE];
public Client(Socket socket)
{
this.socket = socket;
}
public void ReceiveCallback(IAsyncResult AR)
{
// Handle the received data as usual
}
}
And then in your AcceptCallback method, just use a list of Client instead of Socket, and the final BeginReceive call as such:
var client = new Client(socket);
socket.BeginReceive(client.ReceiveBuffer, 0, BUFFER_SIZE, SocketFlags.None, client.ReceiveCallback,
socket);
clients.Add(newClient);
But again, writing custom networking is hard. Use an existing solution if possible - there's plenty to choose from.
Also, the ObjectDisposedExceptions you're getting are because you're doing Shutdown immediately followed by a Close. This is wrong. TCP shutdown is coöperative - you need to wait for the client socket to close before you call Close on your socket. What you're doing is rudely interrupting the connection before it has a chance to resolve itself. Again - TCP is hard to do right, you need to learn how it works very thoroughly.
I have a simple asynchronous socket server written in C# (pretty much Microsoft's example), however the issue with this example is that it accepts only one message from a client and then shuts down. I want this server to stay alive after receiving any message.
This question has been asked before here, and the answer & comments explain that the resolution to this is simply to call handler.beginReceive within the SendCallback function, however to do this requires passing in a state variable. This is something I am unsure of doing with Async programming as I'm pretty new to it.
With the example below, how can I carry my state object from the Send function to the SendCallback function?
Server code:
// Asynchronous Server Socket Example
// http://msdn.microsoft.com/en-us/library/fx6588te.aspx
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
// State object for reading client data asynchronously
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 1024;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}
public class GetState
{
}
public class AsynchronousSocketListener
{
// Thread signal.
public static ManualResetEvent allDone = new ManualResetEvent(false);
public AsynchronousSocketListener()
{
}
public static void StartListening()
{
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
// The DNS name of the computer
// running the listener is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
// Create a TCP/IP socket.
Socket listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(
state.buffer, 0, bytesRead));
// Check for end-of-file tag. If it is not there, read
// more data.
content = state.sb.ToString();
if (content != null)
{
// All the data has been read from the
// client. Display it on the console.
Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
content.Length, content);
// Echo the data back to the client.
Send(handler, content, state);
}
else
{
// Not all data received. Get more.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
}
}
private static void Send(Socket handler, String data, StateObject state)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
/// ******* WIP ******** //
//handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
//handler.Shutdown(SocketShutdown.Both);
//handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static int Main(String[] args)
{
StartListening();
return 0;
}
}
This is how I would do it:
public class AsynchronousSocketServer
{
private Socket listener;
private byte[] buffer = new byte[8192]; // Buffer to store data from clients.
public void StartListening()
{
listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(new IPEndPoint(localIPAddress, listeningPort));
listener.Listen(20);
listener.BeginAccept(OnSocketAccepted, null);
}
private void OnSocketAccepted(IAsyncResult result)
{
// This is the client socket, where you send/receive data from after accepting. Keep it in a List<Socket> collection if you need to.
Socket client = listener.EndAccept(result);
// Pass in the client socket as the state object, so you can access it in the callback.
client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, OnDataReceived, client); // Start receiving data from this client.
listener.BeginAccept(OnSocketAccepted, null); // Start a new async accept operation to accept incoming connections from other clients.
}
private void OnDataReceived(IAsyncResult result)
{
// This is the client that sent you data. AsyncState is exactly what you passed into the state parameter in BeginReceive
Socket client = result.AsyncState as Socket;
int received = client.EndReceive(result);
// Handle received data in buffer, send reply to client etc...
// Start a new async receive on the client to receive more data.
client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, OnDataReceived, client);
}
}
As you can see it's pretty much a lot of recursive callbacks. The basic idea is that you call BeginAccept to start accepting the first connection, then once your callback fires you accept the connection with EndAccept and start a new BeginAccept to start accepting more connections. This same logic applies to BeginReceive and EndReceive when you start communicating with the clients. With this logic the server will continuously accept incoming connections and clients will also be able to continously send data to server.
In your example you get your listener from the AsyncState but you didn't call BeginAccept again to accept more incoming connections, which probably explains why your server only accepts 1 connection and shuts down.
For the state parameter in BeginSend, you can actually just put your BeginReceive right after your Send() method to save yourself the hassle:
Send(handler, content, state);
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
It's much better to just fire up a background thread and use blocking calls.
Here's a TcpServer using the TcpListener and NetworkStream
public class TcpServer
{
public void Run(string address, int port)
{
var listener = new TcpListener(IPAddress.Parse(address), port);
listener.Start();
while (true)
{
TcpClient tcpclient = null;
NetworkStream netstream = null;
try
{
tcpclient = listener.AcceptTcpClient();
Console.WriteLine("Client connected from " + tcpclient.Client.LocalEndPoint.ToString());
netstream = tcpclient.GetStream();
var responsewriter = new StreamWriter(netstream) { AutoFlush = true };
while (true)
{
if (IsDisconnected(tcpclient))
throw new Exception("Client disconnected gracefully");
if (netstream.DataAvailable) // handle scenario where client is not done yet, and DataAvailable is false. This is not part of the tcp protocol.
{
string request = Read(netstream);
Console.WriteLine("Client sent: " + request);
responsewriter.Write("You sent: " + request);
}
}
}
catch (Exception ex)
{
netstream.Close();
tcpclient.Close();
Console.WriteLine(ex.Message);
}
}
}
private bool IsDisconnected(TcpClient tcp)
{
if (tcp.Client.Poll(0, SelectMode.SelectRead))
{
byte[] buff = new byte[1];
if (tcp.Client.Receive(buff, SocketFlags.Peek) == 0)
return true;
}
return false;
}
private string Read(NetworkStream netstream)
{
byte[] buffer = new byte[1024];
int dataread = netstream.Read(buffer, 0, buffer.Length);
string stringread = Encoding.UTF8.GetString(buffer, 0, dataread);
return stringread;
}
}
To run it
static void Main()
{
ThreadPool.QueueUserWorkItem(w => {
var asyncserver = new TcpServer();
asyncserver.Run("192.168.0.7", 5055); // or whatever your local IP Address is
});
Console.WriteLine("Press [Enter] to quit");
Console.ReadLine();
}
I'm new in Socket programming. I try to write an C# chat. Every time when i call this function:
void starteServer()
{
try {
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress localIpAddress = ipHostInfo.AddressList[0];
IPEndPoint localendpoint = new IPEndPoint(localIpAddress, serverPort);
server.Bind(localendpoint);
server.Listen(10);
Recive(server);
lb_chat.Items.Add(response);
receiveDone.WaitOne();
}
catch (Exception e)
{
errorHandler(e);
}
}
i get an System.Net.SocketException with the reason of an unconnected Socket. I think i breaks in the Recive(server)-line. This is the Recive Method:
private static void Recive(Socket client)
{
try
{
StateObjeckt state = new StateObjeckt();
state.workSocket = client;
client.BeginReceive(state.buffer, 0, StateObjeckt.bufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
catch (Exception e)
{
errorHandler(e);
}
}
private static void ReceiveCallback(IAsyncResult ar)
{
StateObjeckt state = (StateObjeckt)ar.AsyncState;
Socket client = state.workSocket;
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
state.sb.Append(Encoding.UTF8.GetString(state.buffer, 0, bytesRead));
client.BeginReceive(state.buffer, 0, StateObjeckt.bufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
else
{
if (state.sb.Length > 1)
{
response = state.sb.ToString();
}
receiveDone.Set();
}
}
hopefully someone can explain me this behavior and help me fix it.
if you need the rest of the code just visit:
https://gist.github.com/chrishennig/ea4b5a974fc6f9aa2bb6
Thanks in advance
Your problem is you are trying to read data from a listening socket, like it is the socket that is receiving data. When you Listen with a socket, it is only used for calling Accept to accept connections, and then those subsequent connected sockets are then read and written to. So, the exception is telling you that you are trying to read from a socket that isn't connected anywhere, which is correct since no sockets have yet been accepted.
I would like to know if my way of thinking is any good.
Here is sitution:
Server is accepting async for connections. After accept is recieveing async on accepted sockets.
Clients are connecting async to server, then listening for request async.
What I want to do is to send requests from both client and server. Other side should recieve it.
Server code:
public ServerHandler()
{
_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_serverSocket.Bind(_ipLocal);
_serverSocket.Listen(4);
_serverSocket.BeginAccept(AcceptCallback, null);
}
private void AcceptCallback(IAsyncResult ar)
{
Socket socket = (Socket)ar.AsyncState;
_clients.Add(socket);
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, RecieveCallback, socket);
_serverSocket.BeginAccept(AcceptCallback, null);
}
private void RecieveCallback(IAsyncResult ar)
{
var socket = (Socket) ar.AsyncState;
var recieved = socket.EndReceive(ar);
var dataBuff = new byte[recieved];
Array.Copy(_buffer, dataBuff, recieved);
OnMessageRecieved(dataBuff);
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, RecieveCallback, socket);
}
private void Send(byte[] data, Socket socket)
{
socket.BeginSend(data, 0, data.Length, SocketFlags.None,
SendCallback, socket);
}
private void SendCallback(IAsyncResult ar)
{
var socket = (Socket)ar.AsyncState;
socket.EndSend(ar);
}
private void SendToAll(byte[] data)
{
foreach (var clientSocket in _clients)
{
Send(data, clientSocket);
Debug.WriteLine("sent to: " + clientSocket.LocalEndPoint);
}
}
Client code:
public ClientHandler()
{
_ipLocal = new IPEndPoint(IPAddress.Parse(ServerIp), Port);
}
public void ConnectLoop()
{
int attempts = 0;
while (!_clientSocket.Connected)
{
try
{
attempts++;
_clientSocket.BeginConnect(IPAddress.Parse(ServerIp), Port, ConnectCallback, null);
_clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, RecieveCallback,
_clientSocket);
}
catch (Exception)
{
Debug.WriteLine("Connection attempts: " + attempts);
}
}
Debug.WriteLine("Connected");
}
private void ConnectCallback(IAsyncResult ar)
{
_clientSocket.EndConnect(ar);
}
private void RecieveCallback(IAsyncResult ar)
{
var socket = (Socket) ar.AsyncState;
int recieved = _clientSocket.EndReceive(ar);
var dataBuff = new byte[recieved];
Array.Copy(_buffer, dataBuff, recieved);
OnMessageRecieved(dataBuff);
_clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, RecieveCallback, _clientSocket);
}
private void Send(byte[] data, Socket socket)
{
socket.BeginSend(data, 0, data.Length, SocketFlags.None,
SendCallback, socket);
}
private void SendCallback(IAsyncResult ar)
{
var socket = (Socket)ar.AsyncState;
socket.EndSend(ar);
}
Will sth like this work?
EDIT1: Oh, and I want to do it through 1 socket. Client/server sending and recieveing on same socket. But there can be multiple clients sockets, but only 1 for pair client-server.
Without testing, your code looks alright however, you'll need to provide extra code to determine if you've got a whole message or not.
When you do a read, you may get one of the following scenarios:
Some of a message, but not all
exactly all of a message
all of a message plus some/all of another message
a socket error (disconnected etc).
There are a few generally accepted methods of determining what a whole message is:
delimiting your message so your receival code needs to look for the delimiters
A fixed message size with some sort of embedding to indicate if there are more messages
a variable message size but with a fixed "size" part which is transmitted first Ie say the first 4 bytes will indicate the size of the message. So you know you always need 4 bytes first to determine the length of the message; and then you know how much to process for the next message.
This SO post Chat service application has some more and links on processing messages.