I am trying to implement a TCP forwarder in C#. Specifically the application:
Listens to a TCP port and wait for a client,
When a client is connected, connects to a remote host,
Waits for incoming data on the both connections and exchange the data between two endpoints (acts as an proxy),
Closes one connection when the other one get closed by an endpoint.
I have adapted Simple TCP Forwader (by Garcia) to forward a range of ports so that
TCPForwarder.exe 10.1.1.1 192.168.1.100 1000 1100 2000
will forward any packets received on 10.1.1.1 on port 1000-1100 to remote host 192.168.1.100 port 2000-2100. I have employed this to expose a FTP server that is behind a NAT.
By running the above command, the client is able to connect to the FTP server and the following pattern in outputted to the console which is expected (refer to code):
0 StartReceive: BeginReceive
1 StartReceive: BeginReceive
1 OnDataReceive: EndReceive
1 OnDataReceive: BeginReceive
1 OnDataReceive: EndReceive
1 OnDataReceive: Close (0 read)
0 OnDataReceive: EndReceive
0 OnDataReceive: Close (exception)
But after successfully connecting for several times (pressing F5 in Filezilla), no further response is received from TCPForwarder (and FTP Server).
There seems to be two problems with my implementation that I cannot debug:
In that situation, the BeginReceive in StartReceive method gets called, but no data is received from the FTP server. I don't think that could be FTP server issue (it's a ProFTPD server) as it is a well-known FTP server.
Every time a connection is made and closed, the number of threads increases by 1. I don't think garbage collection would fix that. Number of threads is consistently increasing and forcing garabage collector to run doesn't decrease that either. I think there is some leak in my code that is also causing issue #1.
Edit:
Restarting the FTP server didn't fix the problem, so there is definitely a bug in the TCPForwarder.
Some issues pointed out by #jgauffin is fixed in the below code.
Here is the full code:
using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
using System.Threading;
namespace TCPForwarder
{
class Program
{
private class State
{
public int ID { get; private set; } // for debugging purposes
public Socket SourceSocket { get; private set; }
public Socket DestinationSocket { get; private set; }
public byte[] Buffer { get; private set; }
public State(int id, Socket source, Socket destination)
{
ID = id;
SourceSocket = source;
DestinationSocket = destination;
Buffer = new byte[8192];
}
}
public class TcpForwarder
{
public void Start(IPEndPoint local, IPEndPoint remote)
{
Socket MainSocket;
try
{
MainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
MainSocket.Bind(local);
MainSocket.Listen(10);
}
catch (Exception exp)
{
Console.WriteLine("Error on listening to " + local.Port + ": " + exp.Message);
return;
}
while (true)
{
// Accept a new client
var socketSrc = MainSocket.Accept();
var socketDest = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
// Connect to the endpoint
socketDest.Connect(remote);
}
catch
{
socketSrc.Shutdown(SocketShutdown.Both);
socketSrc.Close();
Console.WriteLine("Exception in connecting to remote host");
continue;
}
// Wait for data sent from client and forward it to the endpoint
StartReceive(0, socketSrc, socketDest);
// Also, wait for data sent from endpoint and forward it to the client
StartReceive(1, socketDest, socketSrc);
}
}
private static void StartReceive(int id, Socket src, Socket dest)
{
var state = new State(id, src, dest);
Console.WriteLine("{0} StartReceive: BeginReceive", id);
try
{
src.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, OnDataReceive, state);
}
catch
{
Console.WriteLine("{0} Exception in StartReceive: BeginReceive", id);
}
}
private static void OnDataReceive(IAsyncResult result)
{
State state = null;
try
{
state = (State)result.AsyncState;
Console.WriteLine("{0} OnDataReceive: EndReceive", state.ID);
var bytesRead = state.SourceSocket.EndReceive(result);
if (bytesRead > 0)
{
state.DestinationSocket.Send(state.Buffer, bytesRead, SocketFlags.None);
Console.WriteLine("{0} OnDataReceive: BeginReceive", state.ID);
state.SourceSocket.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, OnDataReceive, state);
}
else
{
Console.WriteLine("{0} OnDataReceive: Close (0 read)", state.ID);
state.SourceSocket.Shutdown(SocketShutdown.Both);
state.DestinationSocket.Shutdown(SocketShutdown.Both);
state.DestinationSocket.Close();
state.SourceSocket.Close();
}
}
catch
{
if (state!=null)
{
Console.WriteLine("{0} OnDataReceive: Close (exception)", state.ID);
state.SourceSocket.Shutdown(SocketShutdown.Both);
state.DestinationSocket.Shutdown(SocketShutdown.Both);
state.DestinationSocket.Close();
state.SourceSocket.Close();
}
}
}
}
static void Main(string[] args)
{
List<Socket> sockets = new List<Socket>();
int srcPortStart = int.Parse(args[2]);
int srcPortEnd = int.Parse(args[3]);
int destPortStart = int.Parse(args[4]);
List<Thread> threads = new List<Thread>();
for (int i = 0; i < srcPortEnd - srcPortStart + 1; i++)
{
int srcPort = srcPortStart + i;
int destPort = destPortStart + i;
TcpForwarder tcpForwarder = new TcpForwarder();
Thread t = new Thread(new ThreadStart(() => tcpForwarder.Start(
new IPEndPoint(IPAddress.Parse(args[0]), srcPort),
new IPEndPoint(IPAddress.Parse(args[1]), destPort))));
t.Start();
threads.Add(t);
}
foreach (var t in threads)
{
t.Join();
}
Console.WriteLine("All threads are closed");
}
}
}
The first problem is that the code will continue on connection failure on the destination socket (the accept loop). Use a continue; in the try/catch. There is also no guarantee that the sockets are still up when you invoke the first BeginReceive. Those calls also need to be wrapped.
Always wrap callback methods in a try/catch as your application can fail otherwise (in this case OnDataRecieve).
Fix that and start to write out the exceptions. They will surely give you a hint about what went wrong.
Related
I'm trying to use generic IP socket objects in .NET. Connecting one of my sockets to another one and sending a few ping-pong messages works just fine.
But now I've implemented a server socket and somehow managed to create Schrödinger's socket.
The server socket handles the incoming connection request just fine, but the connecting socket seems to be connected when I check once but doesn't even have a RemoteEndpoint - though is showing "Connected = true" and it's disconnected when I check the 2nd time.
All sockets are initialized using this function:
private void initSocket() {
if (_socket != null) {
_socket.Dispose();
}
_socket = new Socket(_ownIP.AddressFamily, _socketType, _protocolType);
_socket.Bind(new IPEndPoint(_ownIP, _ownPort));
}
The _socketType is Stream and the _protocolType is Tcp in this case.
The connect function:
public bool connect(string ip, int port, int retries = 3) {
if (_isWaiting) {
throw new InvalidOperationException("Can't connect, when the socket is already waiting for clients.");
}
_wasWaiting = false;
initSocket();
_otherIP = IPAddress.Parse(ip);
_otherPort = port;
IPEndPoint endpoint = new IPEndPoint(_otherIP, _otherPort);
for (int i = 0; i < retries; i++) {
try {
IAsyncResult result = _socket.BeginConnect(endpoint, null, null);
bool success = result.AsyncWaitHandle.WaitOne(_connectTimeout, true);
if (_socket.Connected) {
_socket.EndConnect(result);
_isConnected = true;
return true;
}
else {
_socket.EndConnect(result);
}
}
catch (SocketException e) {
Console.WriteLine(e.Message);
}
}
return false;
}
The server uses this wait function to accept more clients:
private void wait() {
while (_isWaiting) {
try {
_socket.Listen(1);
var newSocket = _socket.Accept();
var newClient = new IPSocket(newSocket, _socketType, _protocolType, new MessageReceivedDelegate(clientReceivedMessage), true);
_clients.Add(newClient.PartnerIP + ":" + newClient.PartnerPort, newClient);
clientConnected(newClient.PartnerIP, newClient.PartnerPort);
while (true) {
Thread.Sleep(10);
}
}
catch (System.Net.Sockets.SocketException ex) {
//Need to find out which one is thrown when no client for accepting available
if (ex.ErrorCode == 2) {
}
Thread.Sleep(10);
}
catch {
Thread.Sleep(10);
}
}
}
The newSocket variable is connected at first and has a valid RemoteEndpoint, but the socket that's connected doesn't route back to newSocket.
I thought that maybe the connection resets when the server socket tries to accept new sockets, so I added the infinite wait loop - which didn't help.
So why does the connecting socket not have any RemoteEndpoint? (it's shown as null)
Since people usually recommend to accept the connection, handle data, close connection:
I want to keep the connection alive and I have to - not doing this is at the time not a solution that I'd consider.
I am having a weird problem where I am making a chat connection with TCPListeners and sockets. For some reason when a client "connects" to the server it will show they have connected twice. Also what is weird once all of the users have connected I will send out a message to all of them. They will respond back with it acknowledged and state that their chat has started.
Things I am noticing with how i have it setup:
It appears according to the log that the user "connects" twice the second "connect occurs once it hits the white(true) loop.
When they send over the acknowledgement back to the server not all of the data is getting sent over. If I do a thread sleep on the client it does appear to start working but it is still inconsistent.
Here is the code:
Server:
private TcpListener tcpListener;
private Thread listen;
private TcpListener tcpUser1, tcpUser2,tcpUser3;
NetworkStream User1Stream,User2Stream,User3Stream;
public event NetworkMessageStringDelegate MessageFromUser;
TcpClient client;
public void start(string ip){
IpHostEntry host = dns.GetHostEntry(dns.GetHostName());
IpAddress[] ip = host.AddressList;
serverStatus = "Server started with IP of: " + ip;
Thread.Sleep(1);
tcpUser1 = new TcpListener(IpAddress.Any, 4001);
listen = new Thread(new ThreadStart(() => ListenUser1(tcpUser1)));
listen.Start();
Thread.Sleep(1);
tcpUser2 = new TcpListener(IpAddress.Any, 4002);
listen = new Thread(new ThreadStart(() => ListenUser2(tcpUser2)));
listen.Start();
Thread.Sleep(1);
tcpUser3 = new TcpListener(IpAddress.Any, 4003);
listen = new Thread(new ThreadStart(() => ListenUser3(tcpUser3)));
listen.Start();
Thread.Sleep(1);
}
public void ListenUser3(TcpListener tmp){
tcpListener = (TcpListener)tmp;
Socket = "Listening for User3";
tcpUser3.Start();
Thread.Sleep(2);
while(true){
user3 = this.tcpListener.AcceptTcpClient();
Thread user3Thread = new Thread(new ParmeterizedThreadStart(receiveUser3Data));
user3Thread.Start(user3);
}
}
//Mostly from MS documenation
private void receiveUser3Data(object client){
client = (TcpClient)client;
User3Stream = client.getStream();
Socket = "Connected to User: " + client.Client.RemoteEndPoint.toString();
byte[] message = new byte[4096];
int total;
//This is the line it will display the socket message Twice. "Connected to User...."
while(true){
total = 0;
try{
do{
total = User3Stream.Read(message,0,4096);
}
while(user3.DataAvailable);
}
catch()
{
Socket = "Error State";
}
}
byte[] infoPacket = new byte[total];
Array.ConstrainedCopy(message,0,infoPacket,total);
if(MessageFromUser3 != null){
MessageFromUser?.Invoke(packet);
}
}
Client:
public void ConfigureUser3(){
try{
socket = new Network.TCPIPClient();
socket.ReceiveMessage() = new Newowrk.TCPIPClient.NetworkMessageStringDelgate(MessageFromserver);
socket.SendMessage() = new Newowrk.TCPIPClient.NetworkMessageStringDelgate(sendMessage);
userThread = new Thread(() => socket.Start("0.0.0.0),4054));
userThread.Start();
}
catch(Exception ex){
}
}
//This is where if I sleep it will send but it is still inconsident
private void SendMEssageToSever(object tmpVal){
object[] sendMessage = tmpVal as object[];
string tmpSendValue = tmpVal[0].ToString();
byte sendValue = Coonvert.ToByte(tmpVal[1]);
packetData[0] = 0;
packetData[1] = sendValue;
packetData[2] = Convert.ToByte(tmpSendValue);
socket.sendMessage = packetData;
}
private voide sendMessage(byte[] userMessage){
try{
if(socket){
outputMessage.Enqueue(userMessage);
while(outputMessage.Count > 0){
Byte[] sendMessage = outputMessage.Dequeue();
string message = ascII.GetString(sendMessage);
if(socket.Connected){
lock(socket){
socket.Send(sendMessage,sendMessage.length,0);
}
}
}
}
}
catch(Exception ex)
}
This code is essentially repeated for all users that are connected to the server.
The TcpListener has asynchronous methods like BeginAcceptTcpClient.
TcpClient.GetStream() (which is a NetworkStream) also has asynchronous methods like BeginRead.
I suggest you change your server code to use these and to store the user state in a class and pass this class to and fro between Begin* and End* methods.
You can support N number of users then, and don't have to repeat code for each user. You also don't have to have 3 different listeners for 3 connections. Have just one listener and accept clients over this one. The rest is two-way communication via TcpClient.GetStream()
Here is a minimal server example which listens on port 9988 (for only LoopBack, which means the local machine). You can of course change this.
There is no client example here. Only the server. Just copy/paste the code into your program.cs file in a console application.
I hope the comments are sufficient to explain the code.
I hope also, that this helps.
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
class Program
{
/// <summary>
/// Contains the state for a client connection
/// </summary>
public class ClientState
{
public const int ReceiveBufferSize = 8192;
// The buffer to receive in
internal byte[] receiveBuffer = new byte[ReceiveBufferSize];
// The TcpClient instance representing the remote end (connected client)
public TcpClient TcpClient { get; set; }
public byte[] GetReceiveBuffer()
{
return receiveBuffer;
}
}
// This method is invoked when data is received from a client
static void OnReceive(IAsyncResult asyncResult)
{
// The state parameter passed to the BeginRead method
// is provided here in the asyncResult.AsyncState property
ClientState clientState = asyncResult.AsyncState as ClientState;
int numberOfBytesReceived = clientState.TcpClient.GetStream().EndRead(asyncResult);
if (numberOfBytesReceived == 0)
{
// This means that the transmission is over
Console.WriteLine("Client disconnect: {0}", clientState.TcpClient.Client.RemoteEndPoint);
return;
}
// Now the receiveBuffer is filled with <numberOfBytesReceived> bytes received from the client.
// Do whatever is needed here.
Console.WriteLine("Received {0} bytes from {1}", numberOfBytesReceived, clientState.TcpClient.Client.RemoteEndPoint);
// We are also sending some information back:
StreamWriter streamWriter = new StreamWriter(clientState.TcpClient.GetStream());
streamWriter.WriteLine("The server has received {0} bytes from you! Keep up the good job!", numberOfBytesReceived);
streamWriter.Flush();
// Begin read again
clientState.TcpClient.GetStream().BeginRead(clientState.GetReceiveBuffer(), 0, ClientState.ReceiveBufferSize, OnReceive, clientState);
}
// This method is invoked when a new client connects
static void OnConnect(IAsyncResult asyncResult)
{
// The state parameter passed to the BeginAcceptTcpClient method
// is provided here in the asyncResult.AsyncState property
TcpListener tcpListener = asyncResult.AsyncState as TcpListener;
// Accept the TcpClient:
TcpClient newClient = tcpListener.EndAcceptTcpClient(asyncResult);
// Immediately begin accept a new tcp client.
// We do not want to cause any latency for new connection requests
tcpListener.BeginAcceptTcpClient(OnConnect, tcpListener);
// Create the client state to store information aboutn the client connection
ClientState clientState = new ClientState()
{
TcpClient = newClient
};
Console.WriteLine("A new client has connected. IP Address: {0}", newClient.Client.RemoteEndPoint);
// Start receiving data from the client
// Please note that we are passing the buffer (byte[]) of the client state
// We are also passing the clientState instance as the state parameter
// this state parameter is retrieved using asyncResult.AsyncState in the asynchronous callback (OnReceive)
newClient.GetStream().BeginRead(clientState.GetReceiveBuffer(), 0, ClientState.ReceiveBufferSize, OnReceive, clientState);
// Nothing else to do.
// The rest of the communication process will be handled by OnReceive()
}
static void Main()
{
// Start a tcp listener
TcpListener tcpListener = new TcpListener(IPAddress.Loopback, 9988);
tcpListener.Start();
// Begin accept a new tcp client, pass the listener as the state
// The state is retrieved using asyncResult.AsyncState in the asynchronous callback (OnConnect)
tcpListener.BeginAcceptTcpClient(OnConnect, tcpListener);
// That's it. We don't need anything else here, except wait and see.
Console.WriteLine("Server is listening on port 9988. Press enter to stop.");
Console.ReadLine();
}
}
What I am trying to do is just check the messages that the client is sending.
what I want is to maintain the socket that was created open and just check the get message that the client send from time to time.
I am using System.Net.Sockets only, I want to make an implementation based on barkeley sockets.
Here is my code,
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Runtime.Remoting.Metadata.W3cXsd2001;
namespace Socket_v1._0
{
class Program
{
private const int BUFSIZE = 200;// Size of receive buffer
private const int BACKLOG = 5; // O valor backlog define o número de pedidos de conexão que podem ser mantidos em espera sem serem aceites pela "system-call" accept.
static void Main(string[] args)
{
int servPort = 8070; //port number
Socket server = null;
try
{
// Create a socket to accept client connections
server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
server.Bind(new IPEndPoint(IPAddress.Any, servPort));
server.Listen(BACKLOG);
}
catch (SocketException se)
{
Console.WriteLine(se.ErrorCode + ": " + se.Message);
Environment.Exit(se.ErrorCode);
}
//for now the server socket is waiting for connections
byte[] rcvBuffer = new byte[BUFSIZE]; // definir buffer
int bytesRcvd = 0 ; // numero de bytes recebidos
for (; ; )
{ // Run forever, accepting and servicing connections
Socket client = null;
try
{
client = server.Accept(); // Get client connection
Console.Write("Handling client at " + client.RemoteEndPoint + " - ");
do {
bytesRcvd = client.Receive(rcvBuffer, 0, rcvBuffer.Length, SocketFlags.None);
string s = Encoding.ASCII.GetString(rcvBuffer, 0, bytesRcvd);
}while (true);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
client.Close();
}
}
}
}
}
So the client send a http get from time to time, i want to see those messages,
for now for the first time this runs the string gets the http get, and because I am maintaining the socket open, I want to wait for the next message (do{}(while(true))).
it goes back to the client.receive, and stops.
after detecting another message from the client it enters in forever loop and the string is empty.
I want something similar to a chat, where the client send messages and the server display the message.
So after opening the socket, what should i do to get the message from the client, then display it , then wait for another message?
One other thing that is bugging me is the client http get:
this is the http get
GET /iclock/cdata?SN=2182682370001&options=all&pushver=2.1.2&language=80 HTTP/1.1
Host: 192.168.1.43:8070
User-Agent: iClock Proxy/1.09
Connection: close
Accept: * / *
What does it mean when it says connection close? do i need create a new socket every time the client want to send a request?
Try to figure it out, i did some changes on the code, inside the do while i have got this
while ((bytesRcvd = client.Receive(rcvBuffer/*, 0, rcvBuffer.Length, SocketFlags.None*/)) > 0)
{
totalBytesEchoed += bytesRcvd;
string s = Encoding.ASCII.GetString(rcvBuffer, 0, bytesRcvd);
Console.WriteLine(s);
}
Image:
so in the image i have got wireshark running and my console app.
according to wireshark the client had tried to send 2 http request, but according to the console it only displayed one...
i want to display the two calls..
a few years ago, i did some exercises about sockets in c language.
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void main(void)
{
struct sockaddr_in me, from;
int newSock, sock = socket(AF_INET, SOCK_STREAM, 0);
int adl = sizeof(me);
char linha[81];
bzero((char *) &me, adl);
me.sin_family = AF_INET;
me.sin_addr.s_addr = htonl(INADDR_ANY ); /* endereco IP local */
me.sin_port = htons(8450); /* porta local */
if (-1 == bind(sock, (struct sockaddr *) &me, adl))
{
close(sock);
puts("Porta ocupada");
exit(1);
}
listen(sock, 5);
newSock = accept(sock, (struct sockaddr *) &from, &adl);
close(sock);
do
{
read(newSock, linha, 81);
puts(linha);
} while (strcmp(linha, "exit"));
close(newSock);
}
this is in c, so as you can see,after the accept the socket stays open, and the client send the message, it only close the socket when the user send exit to the server...
there may be times where the client doesnt send...but the socket is still open, and when it detects
this is an example of what i want to achive, using the system.net.sockets library,,,
thanks
There are two kinds of sockets: The socket that you use to listen (it is never connected) and the sockets that correspond to connections (each socket represents one connection).
Accept returns you a connected socket to the client that was just accepted. Each call to Accept accepts a new , independent client.
If you want to handle more than one client at a time (which is almost always required) you must ensure that a call to Accept is pending at all times so that new clients can be accepted.
A simple model to achieve this is to accept in a loop forever and start a thread for each client that you accepted:
while (true) {
var clientSocket = listeningSocket.Accept();
Task.Factory.StartNew(() => HandleClient(clientSocket));
}
It might very well be that the client closes the connection.
To detect this on the server side you need to test the result of the call to Receive() against 0.
From MSDN's documentation on Receive() (emphasis by me):
If you are using a connection-oriented Socket, the Receive method will read as much data as is available, up to the number of bytes specified by the size parameter. If the remote host shuts down the Socket connection with the Shutdown method, and all available data has been received, the Receive method will complete immediately and return zero bytes.
From my experience, every time client disconnects from server/listener, this will be registrered on server as SocketException - client has forcibly disconnected. What I do at the moment is just try to catch this and "nicelly" ignore it (log/display some sort of message or run an action to inform the user about this).
Have a look at your code, slightly refactored. Try to run it and see what is happening. I have added some comments to explain a bit. Hope this will help.
There is also class called TcpListenner in .NET you can use to implement behavior you require.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace SimpleListener
{
class Program
{
const int PORT = 8070;
const int BACKLOG = 5;
static Socket socket;
private static byte[] rcvBuffer;
private static int bytesRcvd;
private static string message;
static void Main(string[] args)
{
try
{
StartListener();
Listen();
}
catch (Exception ex)
{
ShowMessage(ex.Message);
}
}
private static void StartListener()
{
try
{
//Initialize socket and start listenning
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(new IPEndPoint(IPAddress.Any, PORT));
socket.Listen(BACKLOG);
ShowMessage("I'm listenning now..");
}
catch (Exception)
{
throw;
}
}
private static void Listen()
{
try
{
rcvBuffer = new Byte[256];
bytesRcvd = 0;
message = string.Empty;
//Start listnening/waiting for client to connect
while (true)
{
var client = socket.Accept();
ShowMessage("Client with IP " + client.RemoteEndPoint.ToString() + " connected!");
//Client has connected, keep receiving/displaying data
while (true)
{
SocketError rcvErrorCode;
bytesRcvd = 0;
message = string.Empty;
bytesRcvd = client.Receive(rcvBuffer, 0, rcvBuffer.Length, SocketFlags.None);
if (rcvErrorCode != SocketError.Success)
{
Console.WriteLine("Client with IP " + client.RemoteEndPoint.ToString() + " disconnected!");
break;
}
message = Encoding.ASCII.GetString(rcvBuffer, 0, bytesRcvd);
Console.WriteLine(DateTime.Now.ToLongTimeString() + " - " + message);
}
}
}
catch (Exception)
{
throw;
}
}
private static void ShowMessage(string message)
{
Console.WriteLine(message);
Console.WriteLine();
}
}
}
Recently I have tackled a strange behaviour of .Net synchronous receive method. I needed to write an application that has nodes which communicate with each other by sending/receiving data. Each server has a receipt loop which is synchronous, after receiving a serialized class it deserializes and processes it. After that it sends asynchronously this serialized class to some chosen nodes (using AsynchSendTo).
The MSDN clearly says that:
"If you are using a connection-oriented Socket, the Receive method
will read as much data as is available, up to the size of the buffer.
If the remote host shuts down the Socket connection with the Shutdown
method, and all available data has been received, the Receive method
will complete immediately and return zero bytes."
In my case it's not true. There are some random cases when the Receive doesn't block and returns 0 bytes (non-deterministic situtation) right away after establishing connection. I'm 100% sure that the sender was sending at lest 1000 bytes. One more funny fact: when putting Sleep(500) before receive everything works just fine. Hereunder is the receiving code:
_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
_listener.Bind(_serverEndpoint);
_listener.Listen(Int32.MaxValue);
while (true)
{
Console.WriteLine("Waiting for connection...");
Socket handler = _listener.Accept();
int totalBytes = 0;
int bytesRec;
var bytes = new byte[DATAGRAM_BUFFER];
do
{
//Thread.Sleep(500);
bytesRec = handler.Receive(bytes, totalBytes, handler.Available, SocketFlags.None);
totalBytes += bytesRec;
} while (bytesRec > 0);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
}
catch (SocketException e)
{
Console.WriteLine(e);
}
Also the sending part:
public void AsynchSendTo(Datagram datagram, IPEndPoint recipient)
{
byte[] byteDatagram = SerializeDatagram(datagram);
try
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.BeginConnect(recipient, ConnectCallback, new StateObject(byteDatagram, byteDatagram.Length, socket));
}
catch (SocketException e)
{
Console.WriteLine(e);
}
}
public void ConnectCallback(IAsyncResult result)
{
try
{
var stateObject = (StateObject)result.AsyncState;
var socket = stateObject.Socket;
socket.EndConnect(result);
socket.BeginSend(stateObject.Data, 0, stateObject.Data.Length, 0, new AsyncCallback(SendCallback), socket);
}
catch (Exception ex)
{
Console.WriteLine("catched!" + ex.ToString());
}
}
public void SendCallback(IAsyncResult result)
{
try
{
var client = (Socket)result.AsyncState;
client.EndSend(result);
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
class StateObject
{
public Byte[] Data { get; set; }
public int Size;
public Socket Socket;
}
My question: am I using the synchronous receive in a wrong way? Why it doesn't block event though there is data to receive?
You're shooting yourself in the foot.
bytesRec = handler.Receive(bytes, totalBytes, handler.Available, SocketFlags.None);
At the very beginning of the connection, Available will be 0, forcing it to return immediately with 0. Instead, you should specify the number of bytes which are free in your buffer (e.g. bytes.Length-totalBytes), then it will also block.
You may have a concurrency problem here. After you accept a connection, you jump straight into receive. The sender process may not have enough time to reach the call to send and so your handler.Available is 0 and the receive returns.
This is also why the "bug" does not occur when you add the sleep of 500 ms.
hey all,
I have made a socket server in C# for a flash game that I am developing, I got the code from somewhere and I am a beginner in c# and .net development . It works fine in practice when connections are made and the server functions correctly. Get 2 concurrent connections at the same time and we have a problem.
here is the basic aspects of the socket server below: (alot taken out for obvious reasons)
how can I alter this so that it can handle concurrent connections? Should I be threading each response?
Thanks
class TcpSock
{
int tcpIndx = 0;
int tcpByte = 0;
byte[] tcpRecv = new byte[1024];
////////////////////////////////////////
public Socket tcpSock;
////////////////////////////////////////
public int Recv(ref string tcpRead)
{
tcpByte = tcpSock.Available;
if (tcpByte > tcpRecv.Length - tcpIndx)
tcpByte = tcpRecv.Length - tcpIndx;
tcpByte = tcpSock.Receive(tcpRecv, tcpIndx, tcpByte,
SocketFlags.Partial);
tcpRead = Encoding.ASCII.GetString
(tcpRecv, tcpIndx, tcpByte);
tcpIndx += tcpByte;
return tcpRead.Length;
}
public int RecvLn(ref string tcpRead)
{
tcpRead = Encoding.ASCII.GetString
(tcpRecv, 0, tcpIndx);
tcpIndx = 0;
return tcpRead.Length;
}
public int Send(string tcpWrite)
{
return tcpSock.Send(Encoding.ASCII.GetBytes(tcpWrite));
}
public int SendLn(string tcpWrite)
{
return tcpSock.Send(Encoding.ASCII.GetBytes(tcpWrite + "\r\n"));
}
}
[STAThread]
static void Main()
{
Thread Server1 = new Thread(RunServer);
Server1.Start();
}
static void RunServer()
{
///class IPHostEntry : Stores information about the Host and is required
///for IPEndPoint.
///class IPEndPoint : Stores information about the Host IP Address and
///the Port number.
///class TcpSock : Invokes the constructor and creates an instance.
///class ArrayList : Stores a dynamic array of Client TcpSock objects.
IPHostEntry Iphe = Dns.Resolve(Dns.GetHostName());
IPEndPoint Ipep = new IPEndPoint(Iphe.AddressList[0], 4444);
Socket Server = new Socket(Ipep.Address.AddressFamily,SocketType.Stream, ProtocolType.Tcp);
///Initialize
///Capacity : Maximux number of clients able to connect.
///Blocking : Determines if the Server TcpSock will stop code execution
///to receive data from the Client TcpSock.
///Bind : Binds the Server TcpSock to the Host IP Address and the Port Number.
///Listen : Begin listening to the Port; it is now ready to accept connections.
ArrayList Client = new ArrayList();
string[,] Users = new string[1000,9];
string rln = null;
string[] Data;
Client.Capacity = 1000;
Server.Blocking = false;
Server.Bind(Ipep);
Server.Listen(32);
Console.WriteLine("Server 1 {0}: listening to port {1}", Dns.GetHostName(), Ipep.Port);
////////////////////////////////////////////////////////////////////////////////////////////
///Main loop
///1. Poll the Server TcpSock; if true then accept the new connection.
///2. Poll the Client TcpSock; if true then receive data from Clients.
while (true)
{
//Accept - new connection
#region new connection
if (Server.Poll(0, SelectMode.SelectRead))
{
int i = Client.Add(new TcpSock());
((TcpSock)Client[i]).tcpSock = Server.Accept();
Console.WriteLine("Client " + i + " connected.");
Users[i, 0] = i.ToString();
}
#endregion
for (int i = 0; i < Client.Count; i++)
{
//check for incoming data
if (((TcpSock)Client[i]).tcpSock.Poll(0, SelectMode.SelectRead))
{
//receive incoming data
if (((TcpSock)Client[i]).Recv(ref rln) > 0)
{
Console.WriteLine(rln.ToString());
Data = rln.Split('|');
// 1) initial connection
#region InitialConnection
if (Data[0] == "0000")
{
}
}
}
}
}
}
You will need to not use synchronous functions but asynchrounus functions like Socket.BeginReceive
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
public static partial class TcpServer
{
public static void Main()
{
// Setup listener on "localhost" port 12000
IPAddress ipAddr = Dns.GetHostEntry("localhost").AddressList[0];
TcpListener server = new TcpListener(ipAddr, 12000);
server.Start(); // Network driver can now allow incoming requests
// Accept up to 1 client per CPU simultaneously
Int32 numConcurrentClients = Environment.ProcessorCount;
for (Int32 n = 0; n
private static Byte[] ProcessData(Byte[] inputData)
{
String inputString = Encoding.UTF8.GetString(inputData, 1, inputData[0]);
String outputString = inputString.ToUpperInvariant();
Console.WriteLine("Input={0}", inputString);
Console.WriteLine(" Output={0}", outputString);
Console.WriteLine();
Byte[] outputStringBytes = Encoding.UTF8.GetBytes(outputString);
Byte[] outputData = new Byte[1 + outputStringBytes.Length];
outputData[0] = (Byte)outputStringBytes.Length;
Array.Copy(outputStringBytes, 0, outputData, 1, outputStringBytes.Length);
return outputData;
}
}
public static partial class TcpServer
{
private sealed class ClientConnectionApm
{
private TcpListener m_server;
private TcpClient m_client;
private Stream m_stream;
private Byte[] m_inputData = new Byte[1];
private Byte m_bytesReadSoFar = 0;
public ClientConnectionApm(TcpListener server)
{
m_server = server;
m_server.BeginAcceptTcpClient(AcceptCompleted, null);
}
private void AcceptCompleted(IAsyncResult ar)
{
// Connect to this client
m_client = m_server.EndAcceptTcpClient(ar);
// Accept another client
new ClientConnectionApm(m_server);
// Start processing this client
m_stream = m_client.GetStream();
// Read 1 byte from client which contains length of additional data
m_stream.BeginRead(m_inputData, 0, 1, ReadLengthCompleted, null);
}
private void ReadLengthCompleted(IAsyncResult result)
{
// If client closed connection; abandon this client request
if (m_stream.EndRead(result) == 0) { m_client.Close(); return; }
// Start to read 'length' bytes of data from client
Int32 dataLength = m_inputData[0];
Array.Resize(ref m_inputData, 1 + dataLength);
m_stream.BeginRead(m_inputData, 1, dataLength, ReadDataCompleted, null);
}
private void ReadDataCompleted(IAsyncResult ar)
{
// Get number of bytes read from client
Int32 numBytesReadThisTime = m_stream.EndRead(ar);
// If client closed connection; abandon this client request
if (numBytesReadThisTime == 0) { m_client.Close(); return; }
// Continue to read bytes from client until all bytes are in
m_bytesReadSoFar += (Byte)numBytesReadThisTime;
if (m_bytesReadSoFar
private void WriteDataCompleted(IAsyncResult ar)
{
// After result is written to client, close the connection
m_stream.EndWrite(ar);
m_client.Close();
}
}
}
First of all: Stop using non-blocking sockets. In .NET you should either stick to the synchronous methods Receive/Send or asynchronous methods BeginReceive/BeginSend.
You should only stick with sync methods if you will have only a handful of clients. Then launch each new client in a new thread. This is the easiest option to get everthing running.
Simply do like this:
public void AcceptClients()
{
TcpListener listener = new TcpListener(IPAddress.Any, 5566);
listener.Start();
while (_serverRunning)
{
var socket = listener.AcceptSocket();
new Thread(ClientFunc).Start(socket);
}
}
public void ClientFun(object state)
{
var clientSocket = (Socket)state;
var buffer = new byte[65535];
while (_serverRunning)
{
//blocking read.
clientSocket.Receive(buffer, 0, buffer.Length, SocketFlags.None);
//check packet.
// handle packet
// send respons.
clientSocket.Send(alalalal);
}
}
You should refactor the methods so that they follow SRP. The code is just a small guide to get you going.