Server/Client Socket Connection issue - c#

First of all, what my Project should do if it would work:
Client written in C++ connects to Server coded in C#
When Connection was successfully, Client sends "0" to the Server to request a random String of Hexadecimals
If the Client recieved the Hexadecimals he will send "1" to the Server
Now the Client does some Stuff with the recieved Hexadecimalstring and then sends it back to the Server
if what the client did to the Hexadecimalstring was correct(Basic authing System) he returns "1" otherwise he returns "0"
Note: The recieving/sending on Client/Server side works, i tested it before by just sending 1 to the Server and the Server returns 0 if the recieved String was 1
Now to my Coding:
Thats the Server Part written in C#:
private static Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private static List<Socket> clientSockets = new List<Socket>();
private const int PORT = 11111;
private static byte[] buffer = new byte[100];
private void ReceiveCallback(IAsyncResult AR)
{
Socket current = (Socket)AR.AsyncState;
int received;
try
{
received = current.EndReceive(AR);
}
catch (SocketException)
{
Console.WriteLine("Client Disconnected! (Forced)");
current.Close();
clientSockets.Remove(current);
return;
}
//That's how my Example before worked:
/*byte[] recBuf = new byte[1];
Array.Copy(buffer, recBuf, received);
string text = Encoding.ASCII.GetString(recBuf);
if(text != "" && text.StartsWith("0"))
{
Console.WriteLine("Recieved: " + text);
string send = "1";
Console.WriteLine("Sending: " + send);
Byte[] data = ASCIIEncoding.ASCII.GetBytes(send);
current.Send(data);
Console.WriteLine("Sended!");
current.Shutdown(SocketShutdown.Both);
current.Close();
clientSockets.Remove(current);
Console.WriteLine("Client Disconnected!");
return;
}
current.BeginReceive(buffer, 0, 1, SocketFlags.None, ReceiveCallback, current);*/
//worked like a charm!
//That's my new Solution, that doesn't work:
byte[] recBuf = new byte[100];
Array.Copy(buffer, recBuf, received);
string text = Encoding.ASCII.GetString(recBuf);
while (text != "")
{
Console.WriteLine("Received Data: " + text);
if (text.StartsWith("0") && text.Length < 32)
{
Console.WriteLine("Client requests Random HexString...");
string rand = GetRandomHexNumber(32);
Byte[] data = ASCIIEncoding.ASCII.GetBytes(rand);
current.Send(data);
Console.WriteLine("Sended HexString! - " + rand);
}
if (text.StartsWith("1") && text.Length < 32)
{
Console.WriteLine("Client recieved the HexString!");
}
if (text.Length > 32 && !text.StartsWith("0") && !text.StartsWith("1"))
{
Console.WriteLine("Result recieved!");
//here will be some authing process but for simplicity just return "1"
byte[] data = ASCIIEncoding.ASCII.GetBytes("1");
current.Send(data);
current.Shutdown(SocketShutdown.Both);
current.Close();
clientSockets.Remove(current);
Console.WriteLine("Client Disconnected!");
return;
}
if (current.Connected)
current.BeginReceive(buffer, 0, 100, SocketFlags.None, ReceiveCallback, current);
}
if (current.Connected)
current.BeginReceive(buffer, 0, 100, SocketFlags.None, ReceiveCallback, current);
}
private void AcceptCallback(IAsyncResult AR)
{
Socket socket;
try
{
socket = serverSocket.EndAccept(AR);
}
catch (ObjectDisposedException)
{
return;
}
clientSockets.Add(socket);
socket.BeginReceive(buffer, 0, 100, SocketFlags.None, ReceiveCallback, socket);
Console.WriteLine("Client Connected!");
serverSocket.BeginAccept(AcceptCallback, null);
}
private void setupServer()
{
serverSocket.Bind(new IPEndPoint(IPAddress.Any, PORT));
serverSocket.Listen(0);
Console.WriteLine("Server Started!");
Console.WriteLine("Listening for Clients...");
serverSocket.BeginAccept(AcceptCallback, null);
}
private void CloseAllSockets()
{
foreach (Socket socket in clientSockets)
{
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
serverSocket.Close();
}
setupServer(); gets launched on Console startup!
The C# part is the only problematic on the c++ side everything is fine!
I really hope somebody is able to help me now, since i didn't recieved any kind of help yet on this forum and i'm really in need for this to work and i'm sure here are plenty of programmers that could help me(maybe it's just a logical issue so every answer or comment is appreciated)
Thanks for your time :)

Replace
while (text != "")
{
// .....................
if (current.Connected)
current.BeginReceive(buffer, 0, 100, SocketFlags.None, ReceiveCallback, current);
}
if (current.Connected)
current.BeginReceive(buffer, 0, 100, SocketFlags.None, ReceiveCallback, current);
with
if (text != "")
{
// .....................
// Notice there's no BeginReceive() here!
}
if (current.Connected)
current.BeginReceive(buffer, 0, 100, SocketFlags.None, ReceiveCallback, current);
The function passed as callback paramater to BeginReceive() normally should not call BeginReceive() in a loop "until session is over". Instead it should call the BeginReceive() only once to pend another read operation if further data is expected (i.e. "session in not over").

Related

How to send images via socket server? (Not TCPClient)

I have a problem with sending or receiving image (I don't know which part fails because my image is getting cutted on receive). I know that this kind of problem has much posts about it but any of these wasn't working for me.
So simply I have "my" socket server (not TCPClient). Server have to get screenshot of screen and send it to the client.
private static void ReceiveCallback(IAsyncResult AR)
{
Socket current = (Socket)AR.AsyncState;
int received;
IPEndPoint remoteIpEndPoint = current.RemoteEndPoint as IPEndPoint;
try
{
received = current.EndReceive(AR);
}
catch (SocketException)
{
current.Close();
return;
}
byte[] recBuf = new byte[received];
Array.Copy(buffer, recBuf, received);
string text = Encoding.ASCII.GetString(recBuf);
Console.ForegroundColor = ConsoleColor.DarkGray;
Console.Write("Received Text: ");
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine(text);
if(text.ToLower() == "screenshot")
{
Image a = get_image.doscreen();
current.Send(ImageToByte(a));
}
if(current.Connected)
current.BeginReceive(buffer, 0, BUFFER_SIZE, SocketFlags.None, ReceiveCallback, current);
}
I know that's not much code to show but I've done this server from tutorial and whole code it's pretty basic. Also I know that it might be buffer problem but I don't know how to fix this.
"My" client code:
private static void send()
{
try
{
string req = Console.ReadLine();
byte[] buffer = Encoding.ASCII.GetBytes(req);
_clientsocket.Send(buffer);
byte[] receivedbuf = new byte[1024];
int rec = _clientsocket.Receive(receivedbuf, receivedbuf.Length, SocketFlags.None);
byte[] data = new byte[rec];
Array.Copy(receivedbuf, data, rec);
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine(Encoding.ASCII.GetString(data));
if (req.ToLower() == "screenshot")
{
File.WriteAllBytes("test.png", data);
}
}
catch(Exception){
}
}

Socket multiple client one server

How can I stop sending message to a client, while client do not read a message from server. To better understand what this means, consider a scenario in which a client does not call Read for an extended period of time, and server stops sending message to this client.
Server.cs receive message from client, and send to all clients
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");
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);
buffQueue.Enqueue(text);
current.BeginReceive(buffer, 0, BUFFER_SIZE, SocketFlags.None, ReceiveCallback, current);
foreach (var client in clientSockets)
{
foreach (var msg in buffQueue)
{
Sendata(client, text);
}
}
}
static void Sendata(Socket socket, string noidung)
{
byte[] data = Encoding.ASCII.GetBytes(noidung);
socket.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket);
}
private static void SendCallback(IAsyncResult AR)
{
Socket socket = (Socket)AR.AsyncState;
socket.EndSend(AR);
}
Client.cs
public void ReceiveMessage(IAsyncResult ar)
{
Random rnd = new Random();
Socket socket = (Socket)ar.AsyncState;
int received = socket.EndReceive(ar);
byte[] dataBuf = new byte[received];
Array.Copy(receivedBuf, dataBuf, received);
string msg = Encoding.ASCII.GetString(dataBuf);
Console.WriteLine("> " + msg + '\n');
ClientSocket.BeginReceive(receivedBuf, 0, receivedBuf.Length, SocketFlags.None,
new AsyncCallback(ReceiveMessage), ClientSocket);
}
The problem is, that when a client does not read the buffer, the receivebuffer of the client will be full and the server will block in execution. You could prevent this by either:
Queue the data for each client. The client must request data, so the server will send it's queue. (on a different thread)
Use the socket.Blocking = false on the socket on the server. When the server is sending the data and the buffers are full, you'll get an WouldBlock exception or when using the right overload on sending, a SocketErrorCode is returned. Windows Sockets: Blocking. You still need a queue.
The SendData could be done parallel, because the bytebuffer/data doesn't change while sending.

C# Socket does not send complete data

I am trying to create a client/server application where a server sends commands to clients and clients send result back. The clients send data like this:
5|Hello
5 is the length of the string which is sent because then the server knows howmany characters it should receive before it should do something with that data. I tried to do that with this code:
private static void ReceiveCallback(IAsyncResult AR)
{
try
{
while (!Encoding.ASCII.GetString(_buffer).Contains("|"))
{
}
string[] a = Encoding.ASCII.GetString(_buffer).Split('|');
while (Encoding.ASCII.GetString(_buffer).Length < (Int32.Parse(a[0]) + a[0].Length + 1))
{
}
Socket socket = (Socket)AR.AsyncState;
int received = socket.EndReceive(AR);
byte[] dataBuf = new byte[received];
Array.Copy(_buffer, dataBuf, received);
string text = Encoding.ASCII.GetString(dataBuf);
if (!text.Contains("GET") && !text.Contains("HTTP") && text != null)
{
Console.WriteLine(DateTime.Now.ToString("h:mm:ss tt") + ":" + text);
}
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
}
catch
{
}
}
but this still does not give me the correct result. Also the CPU goes very high.
Picture of the result:
Can someone explain me why this happens? Thanks!
try to replace Encoding.ASCIIto Encoding.UTF8.
It can fix you issue.
Do note that you must to use the same encoding on both sides (sending and receiving data).
I hope it helps you.
have you tried using TcpClient? it can be way easier and gives you more control.
something like;
//make connection
NetworkStream stream = null;
socket = new TcpClient();
socket.Connect("192.168.12.12", 15879);
if (socket.Connected) {
stream = socket.GetStream();
}
//and than wait for tcp packets.
connectionThread = new Thread(ListenServer);
connectionThread.Start();
private void ListenToServer() {
Byte[] data = new Byte[1024];
String message = String.Empty;
Int32 dataLength = 0;
while (socket.Connected) {
try {
while (stream.DataAvailable) {
dataLength = stream.Read(data, 0, data.Length);
message = System.Text.Encoding.UTF8.GetString(data, 0, dataLength);
//do what ever you need here
Thread.Sleep(1);
}
} catch (Exception ex) {
}
Thread.Sleep(100);
}
moreover %1 cpu load!

Clients and Server Listening for requests

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.

C# Sockets and sending data to all clients

OK, so I am not very good at programming in general, but I want to try my hand at using sockets. To start I watched a Youtube video which I followed step by step, I got the finished product working 100% to the guides however I wish to modify it in order for the server to be able to send a message to all connected clients.
Here is the youtube video: Youtube Video - Sockets
So this is the code for the server class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
namespace Server
{
class Program
{
private static byte[] buffer = new byte[1024];
public static Socket _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public static List<Socket> clientSockets = new List<Socket>();
static void Main(string[] args)
{
Console.Title = "Server, " + clientSockets.Count.ToString() + " clients are connected";
SetupServer();
Console.ReadLine();
}
public static void SetupServer()
{
Console.WriteLine("Setting up server...");
_serverSocket.Bind(new IPEndPoint(IPAddress.Any, 100));
_serverSocket.Listen(5);
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
public static void AcceptCallback(IAsyncResult AR)
{
Socket socket = _serverSocket.EndAccept(AR);
clientSockets.Add(socket);
Console.WriteLine("Client Connected");
Console.Title = "Server, " + clientSockets.Count.ToString() + " clients are connected";
socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(RecieveCallBack), socket);
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
private static void RecieveCallBack(IAsyncResult AR)
{
Socket socket = (Socket)AR.AsyncState;
int received = socket.EndReceive(AR);
byte[] databuff = new byte[received];
Array.Copy(buffer, databuff, received);
string s = Encoding.ASCII.GetString(databuff);
Console.WriteLine("Text Received: " + s);
string response = string.Empty;
if (s.ToLower() == "get time")
{
response = DateTime.Now.ToLongTimeString();
}
else
{
response = "Invalid Request";
}
byte[] data = Encoding.ASCII.GetBytes(response);
socket.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(sendCallback), socket);
socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(RecieveCallBack), socket);
}
private static void sendCallback(IAsyncResult AR)
{
Socket socket = (Socket)AR.AsyncState;
socket.EndSend(AR);
}
}
}
I had a pretty pathetic attempt at what I wanted to do:
private static void RecieveCallBack(IAsyncResult AR)
{
Socket socket = (Socket)AR.AsyncState;
int received = socket.EndReceive(AR);
byte[] databuff = new byte[received];
Array.Copy(buffer, databuff, received);
string s = Encoding.ASCII.GetString(databuff);
Console.WriteLine("Text Received: " + s);
foreach(Socket s1 in clientSockets){
string response = string.Empty;
if (s.ToLower() == "get time")
{
response = DateTime.Now.ToLongTimeString();
}
else
{
response = "Invalid Request";
}
byte[] data = Encoding.ASCII.GetBytes(response);
s1.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(sendCallback), s1);
s1.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(RecieveCallBack), s1);
}
}
wasn't really expecting it too work, but I gave it a go.
Another secondary question:
Is this the line of code which determines what IP and Port the server will be listening on?
_serverSocket.Bind(new IPEndPoint(IPAddress.Any, 100));
Used the same code, had the same problem.
It is not working because the client console is stuck in readLine(), so it is not receiving responses. After you send a command don't call Console.ReadLine again.
To loop trough all clients and send a message:
private static void sentToAll(string s)
{
foreach (Socket socket in clientSockets)
{
byte[] data = Encoding.ASCII.GetBytes(s);
socket.Send(data);
}
}
private static IPEndPoint localEndPoint;
public static String IpAddress = "10.0.0.13";
public static int port = 3000;
localEndPoint = new IPEndPoint(IPAddress.Parse(IpAddress), port);
_serverSocket.Bind(localEndPoint);

Categories