I'm working on a chat/IM system for my game (which is written in Flex) and wanted to connect it to my server (which is written in C#) via sockets.
So, I've successfully connected them together using XMLSocket on Flex, and Socket on the server side, the client gets a connected event, sends data correctly, but when I try to send back data from the server to the client, nothing happens (even though the BeginSend callback shows that the entire buffer was sent).
Client:
private var hostName:String = "localhost";
private var port:uint = 4444;
private var socket:XMLSocket;
public var app:DotNETServerTest;
public function DotNetSocketExample() {
socket = new XMLSocket();
configureListeners(socket);
socket.connect(hostName, port);
}
public function send(data:Object):void {
socket.send(data);
}
public function disconnect():void {
socket.close();
closeHandler(null);
}
private function configureListeners(dispatcher:IEventDispatcher):void {
dispatcher.addEventListener(Event.CLOSE, closeHandler);
dispatcher.addEventListener(Event.CONNECT, connectHandler);
dispatcher.addEventListener(DataEvent.DATA, dataHandler);
}
private function closeHandler(event:Event):void {
trace("closeHandler: " + event);
app.send_btn.enabled = false;
app.disconnect_btn.enabled = false;
}
private function connectHandler(event:Event):void {
trace("connectHandler: " + event);
app.send_btn.enabled = true;
app.disconnect_btn.enabled = true;
}
private function dataHandler(event:DataEvent):void {
trace("dataHandler: " + event);
Alert.show(event.data);
}
Server (Only specific parts):
// This is the call back function, which will be invoked when a client is connected
public static void OnClientConnect(IAsyncResult asyn)
{
try
{
SocketClient NewConnection = new SocketClient(SocketServer.EndAccept(asyn));
// This is a test message I'm attempting to send
SendMessageTo(NewConnection, "<test></test>");
Clients.Add(NewConnection);
WaitForData(NewConnection);
LogMessage(NewConnection, "Client # {0} connected", Clients.Count);
SocketServer.BeginAccept(new AsyncCallback(OnClientConnect), null);
}
catch (ObjectDisposedException)
{
LogMessage("OnClientConnection: Socket has been closed.");
}
catch (SocketException se)
{
Console.WriteLine(se.Message);
}
}
internal static void SendMessageTo(SocketClient client, string Data)
{
byte[] byteData = Encoding.ASCII.GetBytes(Data);
SendMessageTo(client, byteData);
}
internal static void SendMessageTo(SocketClient client, byte[] byteData)
{
try
{
client.socket.BeginSend(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(SendCallback), client);
}
catch (Exception e)
{
LogMessage(client, "Error sending data to client: {0}", e.Message);
}
}
internal static void SendCallback(IAsyncResult ar)
{
// Retrieve the socket from the async state object.
SocketClient handler = (SocketClient)ar.AsyncState;
try
{
int bytesSent = handler.socket.EndSend(ar);
}
catch (Exception e)
{
LogMessage(handler, e.Message);
}
}
Please help!
Thanks, Ron
Found the problem - I didn't send out \0 at the end of each send.
Changed this:
byte[] byteData = Encoding.ASCII.GetBytes(Data);
client.socket.BeginSend(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(SendCallback), client);
To this:
byte[] byteData = Encoding.ASCII.GetBytes(Data + "\0");
client.socket.BeginSend(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(SendCallback), client);
Related
I have created a simple C# client application. Once it connects to the server it should read the messages sent from the server. It also has the ability to send messages to server too. However I am unable to figure out to correct way to read the data.
I am spawning a thread once it connects to the server. The thread runs in infinite loop and have two interfaces each for reading and writing. Connect() method is called from a ButtonClick event.
My code snippet is as below:
namespace WpfApp1
{
public class TCPClientClass
{
private StreamWriter SwSender;
NetworkStream Sender;
NetworkStream Receiver;
//private StreamReader SrReciever;
private Thread thrMessaging;
TcpClient tcp;
bool connected = false;
public bool Connected { get { return connected; } set { connected = value; } }
//public bool Connect(IPAddress IP, int nPortNo)
public async Task Connect(IPAddress IP, int nPortNo)
{
tcp = new TcpClient();
try
{
//tcp.Connect(strIPAddress.Parse("192.168.137.1"), 2000);
// tcp.Connect(IP , nPortNo);
await tcp.ConnectAsync(IP, nPortNo);
thrMessaging = new Thread(new ThreadStart(ThreadFunction));
thrMessaging.Start();
Connected = true;
}
catch
{
MessageBox.Show("Unable to connect to server");
//return false;
}
//return true;
}
public void Disconnect()
{
Sender?.Close();
Receiver?.Close();
tcp?.Close();
//tcp?.Client.Disconnect(false);
thrMessaging.Abort();
Connected = false;
}
private void ThreadFunction()
{
while (thrMessaging.IsAlive)
DoTasks();
}
private void DoTasks()
{
if (Connected)
{
var a = ReadMessages();
SendMessages();
}
}
private /*void*/async Task ReadMessages()
{
byte[] data = new byte[4096];
//Int32 bytesRead = 0;
//Task<int> bytesReadTask;
String responseData = String.Empty;
Receiver = tcp.GetStream();
try
{
//bytesReadTask = Receiver.ReadAsync(data, 0, data.Length);
//responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytesReadTask.Result);
var response = await Receiver.ReadAsync(data, 0, data.Length);
MessageBox.Show("Server response was " + response);
Thread.Sleep(1000);
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
private void SendMessages()
{
try
{
string strSendData = "Hello from GUI";
Byte[] data = System.Text.Encoding.ASCII.GetBytes(strSendData);
Sender = tcp.GetStream();
Sender.Write(data, 0, data.Length);
Sender.Flush();
Thread.Sleep(1000);
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
}
}
you should change
var response = await Receiver.ReadAsync(data, 0, data.Length);
MessageBox.Show("Server response was " + response);
to
var response = await Receiver.ReadAsync(data, 0, data.Length);
string result = System.Text.Encoding.Default.GetString(data);
MessageBox.Show("Server response was " + result);
if you´re still having problems..my server Code:
public class tcpServer
{
public void method()
{
TcpListener server = new TcpListener(IPAddress.Any, 9999);
server.Start();
TcpClient client = server.AcceptTcpClient();
NetworkStream ns = client.GetStream();
byte[] hello = new byte[100];
hello = Encoding.Default.GetBytes("hello world");
while (client.Connected)
{
ns.Write(hello, 0, hello.Length);
}
}
}
I have a WPF 'server' app using a socket, with a UWP 'client' app using StreamSocket. I can transfer small amounts of data fine, but if I try and send a 288kb file, the file is received fine by the WPF app but the UWP app never receives the response.
WPF code:
In the ReadCallback method, the content is sent in the format of command;printername{data}. The data is all received fine but the Send method called before processing the data is not received.
public void Start()
{
Task.Run(() =>
{
var ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
var ipAddress = ipHostInfo.AddressList.FirstOrDefault(x =>x.AddressFamily == AddressFamily.InterNetwork);
var localEndPoint = new IPEndPoint(ipAddress, Settings.Default.PrintPort);
listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
IsRunning = true;
while (true)
{
// Set the event to nonsignaled state.
AllDone.Reset();
// Start an asynchronous socket to listen for connections.
listener.BeginAccept(
AcceptCallback,
listener);
// Wait until a connection is made before continuing.
AllDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
});
}
public void AcceptCallback(IAsyncResult ar)
{
if(!IsRunning) return;
// Signal the main thread to continue.
AllDone.Set();
// Get the socket that handles the client request.
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject {WorkSocket = handler};
handler.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0,
ReadCallback, state);
}
public static void ReadCallback(IAsyncResult ar)
{
try
{
// 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.
var content = state.Sb.ToString();
if (content.IndexOf("<EOF>") > -1)
{
content = content.Remove(content.IndexOf("<EOF>"));
if (content.StartsWith("PrintFile"))
{
if (!content.Contains("{"))
{
Send(handler, "false");
return;
}
var parts = content.Substring(0, content.IndexOf('{')).Split(';');
if (string.IsNullOrEmpty(parts[1]))
{
Send(handler, "false");
return;
}
// This send never gets received
Send(handler, "true");
//But the file is printed
var base64 = content.Substring(content.IndexOf('{') + 1);
base64 = base64.Remove(base64.LastIndexOf('}'));
var doc = new Spire.Pdf.PdfDocument(Convert.FromBase64String(base64));
doc.PrintSettings.PrinterName = parts[1];
doc.Print();
}
}
else
{
// Not all data received. Get more.
handler.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0,
ReadCallback, state);
}
}
}
catch
{
//Ignore
}
}
private static void Send(Socket handler, String data)
{
// 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,
SendCallback, handler);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
UWP Code:
public bool PrintFlle(string printer, string base64)
{
try
{
var result = Send($"PrintFile;{printer}{{{base64}}}<EOF>").Result;
return bool.TryParse(result, out var b) && b;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
finally
{
socket.Dispose();
}
}
private async Task<string> Send(string input)
{
try
{
socket = new StreamSocket();
await socket.ConnectAsync(HostName, App.LocalSettings.Values["PrintPort"] as string);
using (Stream outputStream = socket.OutputStream.AsStreamForWrite())
{
using (var streamWriter = new StreamWriter(outputStream))
{
await streamWriter.WriteLineAsync(input);
await streamWriter.FlushAsync();
}
}
using (Stream inputStream = socket.InputStream.AsStreamForRead())
{
using (StreamReader streamReader = new StreamReader(inputStream))
{
var output = await streamReader.ReadLineAsync();
socket.Dispose();
return output;
}
}
}
catch (Exception e)
{
socket.Dispose();
return "";
}
}
I'm trying to implement an async TCP client that sends messages from a queue and listens to the response.
some of the server replies are lost (for example send 7 messages and get only 4 replies) and I don't understand why.
This is not a server issue, since the synchronize version I tested works just fine.
ConcurrentQueue<byte[]> msgQueue = new ConcurrentQueue<byte[]>();
public void Connect()
{
try
{
tcpclnt = new TcpClient();
Console.WriteLine("Connecting.....");
Task.Factory.StartNew(() =>
{
IAsyncResult res = tcpclnt.BeginConnect(_ip, _port, null, null);
if (!res.AsyncWaitHandle.WaitOne(CONNECTION_TIMEOUT_SEC * 1000))
{
tcpclnt.Close();
throw new ApplicationException("timed out trying to connect");
}
tcpclnt.EndConnect(res);
Receive();
byte[] message = null;
while (true)
{
message = null;
msgQueue.TryDequeue(out message);
if (message != null)
{
Stream stm = tcpclnt.GetStream();
Console.WriteLine("Transmitting..... " + Thread.CurrentThread.ManagedThreadId);//for debug
stm.Write(message.ToArray(), 0, message.ToArray().Length);
Receive();
}
}
});
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
//will be called from outside
public void SendMessage(byte[] msg)
{
Console.WriteLine("SendMessage..... " + Thread.CurrentThread.ManagedThreadId);//for debug
msgQueue.Enqueue(msg);
}
private void Receive()
{
SocketError error;
byte[] buffer = new byte[MAX_BUFFER_SIZE];
tcpclnt.Client.BeginReceive(buffer, 0, MAX_BUFFER_SIZE, SocketFlags.None, out error, new AsyncCallback(ReceiveHandler), buffer);
}
private void ReceiveHandler(IAsyncResult ar)
{
System.Console.WriteLine("ReceiveHandler " + Thread.CurrentThread.ManagedThreadId); //for debug
//End current async receive
int bytesRead = tcpclnt.Client.EndReceive(ar);
byte[] resultBuffer = (byte[]) ar.AsyncState;
// do a lot of things with resultBuffer
}
I'm currently working on asynchronous TCP program but I'm having the following issue:
-When the Server sends some stream , the Client first receives an empty buffer and then it receives the stream.
-After the first stream sending,if I'm sending another stream the client's buffer contains the first stream sent and the current
stream.
-If I'm sending another stream, the buffer will contain the stream I sent before and the current one..and so on..
This is really annoying and I don't know where's the problem.
Here is my CLIENT Code:
Socket CLIENT;
byte[] _buffer;
private void button1_Click(object sender, EventArgs e)
{
Start();
}
void Start()
{
CLIENT = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
CLIENT.BeginConnect(IPAddress.Parse("the IPaddress"), 1234, new AsyncCallback(ConnectionCallBack), null);
}
private void ConnectionCallBack(IAsyncResult ar)
{
try
{
CLIENT.EndConnect(ar);
_buffer = new byte[CLIENT.ReceiveBufferSize];
CLIENT.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), null);
}
catch (Exception Er)
{
MessageBox.Show("[[[[ERROR:1]]]]=>" + Er.Message);
}
}
private void ReceiveCallBack(IAsyncResult ar)
{
try
{
int lenght = CLIENT.EndReceive(ar);
if (lenght == 0) { return; }
Array.Resize(ref _buffer, lenght);
string stream = ASCIIEncoding.ASCII.GetString(_buffer);
Array.Resize(ref _buffer, CLIENT.ReceiveBufferSize);
CLIENT.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), null);
}
catch (Exception ex) { MessageBox.Show("[[[[hoERROR:2]]]]=>" + ex.Message); }
}
Here is the server:
private void button2_Click(object sender, EventArgs e)
{
try
{
Socket socket = (Socket)listW.SelectedItems[0].Tag; //contains the socket
socket.BeginSend(_buffer,0,_buffer.Length,SocketFlags.None,new AsyncCallback(SendingCallBack),socket);
ServerSocket.BeginAccept(new AsyncCallback(AcceptCallBack),null);
}
catch (Exception er) { MessageBox.Show("[[[[ERROR:]]]]=>" + er.ToString()); }
}
private void SendingCallBack(IAsyncResult ar)
{
try
{
Socket socket = (Socket)ar.AsyncState;
_buffer = ASCIIEncoding.ASCII.GetBytes(tx1.Text);
socket.BeginSend(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(FinalCallBack),socket);
}
catch (Exception er) { MessageBox.Show("[[[[ERROR:3]]]]=>" + er.ToString()); }
}
private void Final(IAsyncResult ar)
{
Socket client = ar.AsyncState as Socket;
client.EndSend(ar);
}
I think you have a few problems. One seems to be the stream in ReceiveCallback. You get a string from the buffer then do nothing with it. Resizing your buffer down then resizing if back up to the original size seems like a waste. Might was well make a copy of the data then call GetString and you can leave your buffer alone.
In your server, you call BeginSend to send _buffer, when that completes you call BeginSend again in SendingCallback with the binary representation of tx1.Text but you don't call EndSend, when that completes you call EndSend on the 2nd BeginSend; but still haven't called it for the 1st.
I want to do the following with a raw C# socket. I understand that usually the most appropriate way is via HTTP, with a HTTP client. The browser understands that this connection must be kept open in some way.
http://server.domain.com/protocol/do_something.txt
I am trying the following in C#, but have had no luck. What am I doing wrong? Is there a header missing? Should I be encoding what I'm sending to the server in some way? For the ReceiverSocket client, I'm using the following code, but it's just a very standard asynchronous socket client: https://stackoverflow.com/a/10390066/971580
ReceiverSocket socket = new ReceiverSocket("server.domain.com", 80);
socket.Connect();
System.Threading.Thread.Sleep(1000);
String message = "GET /protocol/do_something.txt HTTP/1.1";
message += "\r\n";
message += "\r\n";
socket.Send(message);
The socket can connect successfully, but I don't get any response when I send anything to the server. This is how I am connecting, sending and receiving.t (Apologies: I tried to do this in snippets, rather than including all the methods, but it looked horrid. . .)
public ReceiverSocket(String address, int port) : base(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
{
messageQueue = new Queue<MessageBase>();
IPHostEntry ipHostInfo = Dns.GetHostEntry(address);
IPAddress ipAddress = ipHostInfo.AddressList[0];
remoteEP = new IPEndPoint(ipAddress, port);
}
public void Connect()
{
this.BeginConnect(remoteEP, ConnectCallback, this);
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket)ar.AsyncState;
if (client.Connected)
{
client.EndConnect(ar);
Console.WriteLine("Connect Callback - Connected");
StateObject state = new StateObject();
state.workSocket = client;
state.BufferSize = 8192;
if (SocketConnected != null)
SocketConnected(client);
client.BeginReceive(state.Buffer, state.readOffset, state.BufferSize - state.readOffset, 0, ReceiveCallback, state);
}
else
{
Thread.Sleep(5000);
Connect();
}
}
catch (Exception ex)
{
Reconnect();
}
}
private void ReceiveCallback(IAsyncResult ar)
{
Console.WriteLine("Never gets here. . . ");
try
{
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
if (client.Connected)
{
int bytesRead = client.EndReceive(ar);
foreach (MessageBase msg in MessageBase.Receive(client, bytesRead, state))
{
// Add objects to the message queue
lock (this.messageQueue)
this.messageQueue.Enqueue(msg);
}
if (DataRecieved != null)
DataRecieved(client, null);
client.BeginReceive(state.Buffer, state.readOffset, state.BufferSize - state.readOffset, 0, ReceiveCallback, state);
}
else
{
Reconnect();
}
}
catch (SocketException)
{
Reconnect();
}
}
public void Send(String msg)
{
try
{
byte[] bytes = GetBytes(msg);
if (this.Connected)
{
Console.WriteLine("Sending: " + msg);
this.BeginSend(bytes, 0, bytes.Length, 0, SendCallback, this);
}
else
{
Reconnect();
}
}
catch (SocketException sox)
{
Reconnect();
}
catch (Exception ex)
{
int i = 0;
}
}
static byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
}
public class StateObject
{
public Socket workSocket = null;
public int readOffset = 0;
public StringBuilder sb = new StringBuilder();
private int bufferSize = 0;
public int BufferSize
{
set
{
this.bufferSize = value;
buffer = new byte[this.bufferSize];
}
get { return this.bufferSize; }
}
private byte[] buffer = null;
public byte[] Buffer
{
get { return this.buffer; }
}
}
Shouldn't the fact that I haven't included the message += "Connection: close" header mean that the socket should just start sending whatever data it has asynchronously? Just to note also: I can connect successfuly using Telnet and send the data, just not with a socket yet!
Any pointers at all would be appreciated.
Thanks.
Do NOT call Send() until ConnectCallback() is called first, otherwise you risk sending your data prematurely. Using Sleep() to wait for the connection is wrong.
Do NOT call BeginReceive() until after Send() has finished sending the data.
Because you are using HTTP 1.1, then yes, the connection is kept alive by default if you are connecting to an HTTP 1.1 server. The server's Connection response header will indicate whether the server is actually keeping the connection open or not.
Also, as stated by someone else, HTTP 1.1 requests MUST have a Host header or else the request is malformed and can be rejected/ignored by the server. HTTP 1.1 has a notion of virtual hosts running on the same IP, so the Host header tells the server which host the client wants to talk to.