How to send messages from server to a specific client - c#

I am using WebSockets and trying to set up a code base for my server-client. I know how to send messages from client to server and I also know how to listen those messages from the server side.
However, how can I send a message back to a client ?
// here is the _clientSocket that I accepted
_clientSocket = _serverSocket.Accept();
int received = _clientSocket.Receive(_buffer, 0, _buffer.Length,
SocketFlags.None);
// here is the message I got from the client
string receivedMsg = Encoding.ASCII.GetString(_buffer);
if (receivedMsg == "1")
//TO DO: send back to client "This is a test message from server".

Basically you have to use the SendAsync method:
var sendbuffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes("Whatever text you want to send"));
await socket.SendAsync(sendbuffer , WebSocketMessageType.Text, true, CancellationToken.None)
.ConfigureAwait(false);
Take a look at this example: https://stackoverflow.com/a/26274839/307976

You have to call:
_clientsocket.Send(...);

Related

C# ClientWebSocket doen't receive incoming messages until an outbound message is sent

I'm trying to receive messages from a server in real time, ideally using the ClientWebSocket class. I would like to both send and receive messages on their own. Unfortunately, I always first have to send an outgoing message through WebSocket.SendAsync() and only then new messages arrive with WebSocket.ReceiveAsync(). I tried searching and debugging the code but couldn't find anything that would fix this wrong behavior.
I would like to receive the incoming messages independently of me sending anything. Any help is be appreciated.
public static void WebsocketReceive()
{
while (WebSocket.State == WebSocketState.Open)
{
byte[] receiveBuffer = new byte[2048];
int offset = 0;
while (true)
{
try
{
ArraySegment<byte> bytesReceived = new(receiveBuffer, offset, receiveBuffer.Length);
WebSocketReceiveResult result = await WebSocket.ReceiveAsync(bytesReceived, source.Token);
offset += result.Count;
if (result.EndOfMessage) break;
}
catch { break; };
}
if (offset != 0)
{
Console.WriteLine(Encoding.UTF8.GetString(receiveBuffer, 0, offset));
}
}
}
Edit: more code
This is where I initialize the WebSocket and connect to a server. I don't have access to their code.
WebSocket = new ClientWebSocket();
await WebSocket.ConnectAsync(new Uri("wss://example.com"), Source.Token);
After connecting, I run my WebsocketReceive() method to start collecting incoming messages.
I send messages into the WebSocket from a different method, through this code:
await WebSocket.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes("message to post")), WebSocketMessageType.Text, true, Source.Token);
I should also provide some more details about how the client and server interact. At the start, I send and receive a few responses, which somehow works. I send some messages and receive responses, which are printed into the console.
What isn't working is specifically when the server wants to send me a message on its own. After a few seconds, I should receive incoming events from the server. This is where it stops printing into the console. Whenever I send any message again all of them come back at once - the loop is repeated for all messages in the "queue".

What sort of message does Snapd's API expect?

Snapd has documentation on a REST API.
I'm able to connect to the socket from C# using the following
var snapSocket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP);
var snapEndpoint = new UnixEndPoint("/run/snapd.socket");
snapSocket.Connect(snapEndpoint);
var req = Encoding.ASCII.GetBytes("GET /v2/system-info HTTP/1.1");
snapSocket.Send(req, req.Length, 0);
var bytesReceived = new byte[256];
var bytes = 0;
var response = "";
do
{
bytes = snapSocket.Receive(bytesReceived, bytesReceived.Length, 0);
response = response + Encoding.ASCII.GetString(bytesReceived, 0, bytes);
} while (bytes > 0);
Console.WriteLine(response);
But everything halts at snapSocket.Receive - a response is never sent. I suspect that there's something wrong with the message that I'm sending it.
It turns out that it expects a standard HTTP request, which means a Host: line, a Connection: Close line, and two \ns at the very end are required.
The documentation's following claim...
While it is expected to allow clients to connect using HTTPS over a TCP socket, at this point only a UNIX socket is supported.
... is meant only to imply that HTTPS and TCP do not work yet - HTTP is currently the valid request format even when using the UNIX Socket.
I am not fluent in C# at all, but maybe this python snippet can help lead into a solution:
import requests_unixsocket
session = requests_unixsocket.Session()
r = session.get('http+unix://%2Frun%2Fsnapd.socket/v2/snaps')
r.raise_for_status()
r.json()

UdpClient.Receive(...) doesn't receive any data

I have a socket server (written on C++) which receives requests from clients and sends responses back. So, my test client application (C#) is very simple:
try {
UdpClient udpClient = new UdpClient(10241);
// Connect
udpClient.Connect(server_ip_address, 10240);
// prepare the packet to send
iWritableBuff wbuff = new iWritableBuff();
[ ... ]
// Send
udpClient.Send(wbuff.GetBuff(), (int)wbuff.Written());
// Receive a response
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
Console.WriteLine("We've got some data from the server!!! " + receiveBytes.Length + " bytes.");
udpClient.Close();
} catch (Exception e) {
Console.WriteLine("ERROR: " + e.ToString());
}
I run both applications on the same computer. Server receives a request to port 10240 from the client port 10241 and sends a response back to client port 10241, but client never receive it. So, I'm sure that server sends packet back, because everything works perfectly with C++ client. It means that I'm, doing something wrong on my C# client. Any idea?
Thanks!
P.S.> Just test it with Berkley Socket C# client:
try {
// Create socket
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
// Bind
IPEndPoint myEP = new IPEndPoint(IPAddress.Any, 0);
s.Bind(myEP);
// prepare the packet to send
iWritableBuff wbuff = new iWritableBuff();
[ ... ]
// Send it
IPEndPoint sEP = new IPEndPoint(IPAddress.Parse(server_ip_address), 10240);
int res = s.SendTo(wbuff.GetBuff(), (int)wbuff.Written(), 0, sEP);
// Receive the response
byte[] receiveBytes = new Byte[1024];
EndPoint recEP = new IPEndPoint(IPAddress.Any, 0);
res = s.ReceiveFrom(receiveBytes, ref recEP);
Console.WriteLine("We've got some data from the server!!! " + res + " bytes.");
} catch (Exception e) {
Console.WriteLine("ERROR: " + e.ToString());
}
And it works perfect! What's is wrong with UdpSocket?
Not sure if this applies to UDPClients that don't broadcast packets but simply send one to a specified address, but I ran into a similar roadblock.
I had a UDPClient that broadcasted a udp packet for discovery of some custom machines on our network. When I tried to receive the message that the servers would simply echo back, it would not receive the information and would timeout. Turns out that if you use a UDPClient that broadcasts a message out, it WILL NOT be able to receive messages back. It's not documented anywhere, except for one forum topic on msdn that I luckily came across.
The solution was to send the message, immediately close the socket, open a NEW UDPClient on the same port, then use this new UDPClient to receive the echoed back UDP packet. Very annoying.
Give that a shot and see if it works. It definitely works for sending out a broadcasted packet.

Can't get entire response from proxy C#

I'm building a small HTTP proxy that runs between the browser and squid proxy. The browser sends the HTTP request to my proxy that redirects it to the squid proxy, then my application gets the response from the squid proxy and returns it back to the browser.
the problem is that i can't get the full response from the proxy, i get HTTP 200 OK ... (just the response header), but with out the body then i have to call receive method another time to get the body. but if i debug my code (which make the application slower) it get all the response (response header and body)
is there any propriety in the TCPClass that indicates to me that the remote server still have data to send to me ?
here is my code :
static void Main(string[] args)
{
int ServerPort = 8888;
IPAddress localHost = new IPAddress(0x0100007f);
TcpListener listener = new TcpListener(localHost,ServerPort);
listener.Start();
while(true)
{
string requestString = "";
String respenseString = "";
TcpClient application = listener.AcceptTcpClient();
string source = application.Client.RemoteEndPoint.ToString();
byte[] dataFromApp = new byte[application.ReceiveBufferSize];
application.Client.Receive(dataFromApp);
TcpClient tunnel = new TcpClient("127.0.0.1",8080);
tunnel.Client.Send(dataFromApp);
while (tunnel.Client.Connected ==true)
{
if(tunnel.Available != 0)
{
byte[] responseFromProxy = new byte[tunnel.ReceiveBufferSize];
tunnel.Client.Receive(responseFromProxy);
respenseString += Encoding.UTF8.GetString(responseFromProxy);
}
else
{
break;
}
}
application.Client.Send(Encoding.UTF8.GetBytes(respenseString));
}
You should check the return value of tunnel.Client.Receive and application.Client.Receive. Receive doesn't gurantee that it will read dataFromApp.Length bytes
REMARKS: The Receive method reads data into the buffer parameter and returns the number of bytes successfully read
PS: You may also want to try FiddlerCore to write an Http Proxy
There is no "there are N bytes remaining for this message" property on a socket, because a TCP socket is streaming: it sends and receives bytes, not messages.
HTTP defines messages, and if you are implementing an HTTP proxy, you should be familiar with the HTTP 1.1 RFC. There are various ways to determine the lenght of an HTTP message, all of which you have to implement to make sure you can successfully receive and send HTTP messages.
Thanks guys
I've done it :
while (tunnel.Client.Receive(oneByte) != 0)
{
byte[] responseFromProxy = new byte[tunnel.Available];
tunnel.Client.Receive(responseFromProxy);
application.Client.Send(oneByte);
application.Client.Send(responseFromProxy);
}

Sending custom WCF requests via Sockets

I've seen a few questions left half-answered regarding this topic.
I want to send a request to my self hosted WCF application, which uses NetTcpBinding.
The problem is, I have to use sockets.
I've written a transport binding element which opens a TcpListener(on the ChannelListener OnOpen)
This works fine, but in that case - I'll have to use my own message framing model.
Obviously, I'm not going to implement the net.tcp message framing model( http://msdn.microsoft.com/en-us/library/ff470920%28v=prot.10%29.aspx)
I've read a few posts(including http://blogs.msdn.com/b/carlosfigueira/archive/2008/01/13/writing-custom-requests-to-simple-wcf-services.aspx) which suggest I should send a request and interpret the bytes sent via a MessageEncoder/MessageInspector.
This way, I can basically create a message for each of my methods/operations(with minor
changes per request)
I tried this method and I got the bytes in question(through the use of a custom MessageEncoder) when I used a WCF channel(from a ChannelFactory).
I've saved those bytes, and sent them through a TcpClient - the MessageEncoder wouldn't fire up.
When I Open a normal channel:
ChannelFactory<ITestService> factory = new ChannelFactory<ITestService>(new NetTcpBinding(),
"net.tcp://localhost:76599");
factory.CreateChannel().DoSomething(string.Empty); //gets to MessageEncoder
When I try the same via Sockets:
TcpClient cli = new TcpClient("localhost", 76599);
byte[] fileArray = File.ReadAllBytes("c:\\fileFromMessageEncoder.bin");
cli.GetStream().Write(fileArray, 0, fileArray.Length); // Does not get to MessageEncoder
any ideas?
Finally got it to work.
I initiated the default handshake for a Net.Tcp connection prior to sending the bytes I got via the MessageEncoder.
It's important to note that the endpoint uri must be UTF-8 encoded.
The process is pretty easy - send the negotiation request, send an End Preamble message(0x0C) and wait for the server to return a Preamble Ack message(0x0B).
Then you can send the binary envelope and recieve the response from the WCF application.
I hope this post could help someone in the future.
NegotiationConsts.Via via = new NegotiationConsts.Via(uri);
int arraySize = via.EndpointString.Length +
NegotiationConsts.DefaultRequestLength;
byte[] request = new byte[arraySize];
int count = 0;
request[count++] = NegotiationConsts.Version.RECORD_TYPE;
request[count++] = NegotiationConsts.Version.MAJOR_VERSION;
request[count++] = NegotiationConsts.Version.MINOR_VERSION;
request[count++] = NegotiationConsts.Mode.RECORD_TYPE;
request[count++] = NegotiationConsts.Mode.DUPLEX;
request[count++] = NegotiationConsts.Via.RECORD_TYPE;
request[count++] = via.Length;
via.EndpointString.CopyTo(request,count);
count+=via.EndpointString.Length;
request[count++] = NegotiationConsts.WCFEncoding.RECORD_TYPE;
request[count++] = NegotiationConsts.WCFEncoding.BINARY_ENCODING;
return request;

Categories

Resources