I am writing a proxy application for iSCSI to do some diagnostic work (think Fiddler for iSCSI) - I'm trying to capture data one packet at a time, I don't want to read arbitrary sizes and end up getting all of one iSCSI packet and half of another - I really want to see the same kind of data as Wireshark would display for example. In doing this, I'm using Socket.ReceiveMessageFrom().
However, one of the parameters is called "endpoint", and I'm not quite sure what to do with it. Any clues? Here's my code, can you tell me if I'm completely off base:
Tuple<byte[], int> readOnePacket(TcpClient conn) {
var flags = SocketFlags.None;
EndPoint endpoint = null; /*** You can't set this to null!! ***/
byte[] buffer = new byte[10 * 0x100000];
int offset = 0;
int bytes_received;
do {
IPPacketInformation packet_information;
bytes_received = conn.Client.ReceiveMessageFrom(buffer, offset, BufferSize,
ref flags, ref endpoint, out packet_information);
if (flags == SocketFlags.Partial) {
// We only want to transfer full packets
offset = bytes_received;
continue;
}
} while (false);
return new Tuple<byte[], int>(buffer, bytes_received + offset );
}
It is not TcpClient.ReceiveMessageFrom(), but Socket.ReceiveMessageFrom()
If you take a look at the documentation, you will read the following:
An EndPoint, passed by reference, that
represents the remote server.
Edit:
Setting it to null is, indeed, a bad idea.
While not a direct answer to your question, I think this answer can still be useful (though lots of time passed since the question was asked).
Because I don't know if iSCSI works over TCP or over plain IP, I cannot offer a solution for your problem. But in general, TCP is a stream-oriented protocol, and doesn't have a notion of "message". On the other hand, IP is a datagram (i.e. message) oriented protocol, and it has notion of message. In your code, you're trying to read a "message" (IP construct) from TCP socket, and that will not work. Yes, TCP is based on IP, but IP datagrams are not visible on TCP level.
The problem you've mentioned (read full message, without reading into the next one) is applicable to TCP level only, because on IP you really can read one whole message. When you want the same thing on TCP level, you need to use a protocol with message support. Usually to achieve this you need to have you own protocol, based on TCP, with messages like this:
[msg header][msg body]
where [msg header] consists of something like:
[msg type][msg body length]
Msg type and msg body length have fixed length (say, 2 bytes for msg type and 4 bytes for body length), and msg body can have variable length, so you can read full header, then determine how long the body is, and based on that read full body.
Hope this helps.
Related
We need to create a WCF service for a low bandwidth network. So our goal is to create the binding configuration which produces the smallest number of bytes per call. This is an excerpt from the app.config
<customBinding>
<binding name="binaryBinding">
<binaryMessageEncoding/>
<tcpTransport />
</binding>
</customBinding>
I assume that setting up a connection introduces overhead as well, so we would keep that to a minimum. A typical scenario would be
Client.Connect();
while (!userTerminates())
{
var Response = Client.DoSomething(parameters);
<user input>
var anotherResponse = Client.DoSomethingElse(otherParameters);
}
Client.Close();
The data being sent/received varies from some 20 bytes to a couple of 100.
So far I managed to setup WCF to use netTcpBinding and binary encoding, but I still have an overhead of 400%. I sent a single string of 600 chars and received 2200. I measured this by using a MessageInspector which measures the length of incoming and outgoing messages. I assume that the overhead comes from the SOAP messages.
Edit: Maybe my measuring is wrong.
I also understand that I can compress the communication as shown in the WCF Sample library. GoogleProtocol also seems an option.
But I want to start from the beginning: How can I modify the configuration (or eventually create my own protocol) to minimize the total bytes sent. Security is not an issue at this time, neither is performance, it's only the number of bytes being sent/received I am interested in.
Thanks for any hints.
You're right in that netTcp uses SOAP, which may indeed cause your 20 bytes payload to inflate to more than that.
How to apply a custom binding is explained in CodeProject: CompactMessageEncoder
. If the payload is object-like and you don't call many difference methods, Google's Protocol Buffers and a custom framing protocol over sockets.
The overhead is caused by the fact that WCF serializes objects as XML streams. This means it makes no assumptions about the order or format of the fields it serializes and needs to provide this information with the message. The binary message encoders use the XmlDictionaryReader/Writer to serialize messages and use dictionaries to look up fields that have been transmitted earlier in the session. Still, at some point this information is communicated between client and server which causes extra bytes to be transmitted depending on the size of your data contract.
To reduce payload, consider writing your own serializer as shown here: http://www.codeproject.com/Articles/434665/WCF-Serialization-A-Case-Study.
Also you may consider packaging your data in a single field prior to serialization in the OnSerializing and OnDeserialized methods like so:
[DataContract]
public class Data
{
[DataMember]
private byte data;
private bool bool1;
private bool bool2;
[OnSerializing]
internal void OnSerializing()
{
data = Convert.ToByte((bool1 ? 0 : 1) & (bool2 ? 0 : 2));
}
[OnDeserialized]
internal void OnDeserializing()
{
bool1 = (Convert.ToInt32(data) & 1) != 0;
bool2 = (Convert.ToInt32(data) & 2) != 0;
}
}
I have a huge problem. I write small servers in C#. My clients are JavaScript. JavaScript use HTTP GET to communicate because JavaScript must pass Same Origin Policy. It means I must use HTTP GET to comunication. Now I notice that C# cut (??) my URL.
I sended:
http://172.16.210.25:8000/?callback=ProxyApi.saveStat&cid=1343823765156_495&cidget=null&s[901]=1044!:!5878849%3B6658291%3B2964823%3B1178767%3B469747%3B481939%3B6431323%3B1032649%3B2750603%3B208057%3B9192763%3B6669071%3B2014351%3B6816157%3B3784367%3B1242929%3B4488073%3B7662331%3B2991731%3B6404357%3B8248091%3B1795603%3B4880191%3B3080303%3B4093847%3B4618063%3B7501937%3B2842849%3B6953249%3B7102679%3B5667853%3B9851873%3B5517823%3B6114539%3B6061597%3B7647599%3B4871873%3B400087%3B7514713%3B3958217%3B8163713%3B9560437%3B8229701%3B3408749%3B4432097%3B3353219%3B2936693%3B1343597%3B3490451%3B1266191%3B9125747%3B6152921%3B2689537%3B3796861%3B4987009%3B1206841%3B9278119%3B9499619%3B455627%3B6217051%3B7603201%3B8019079%3B5306033%3B8314939%3B2997221%3B3996221%3B3889649%3B1148507%3B9397139%3B4984949%3B6576473%3B3993247%3B676051%3B5%3B&s[902]=929!:!9012569%3B9836633%3B5239051%3B6102559%3B5944079%3B9749681%3B4007797%3B344821%3B9914917%3B1950227%3B982847%3B6610337%3B6734281%3B4213463%3B1620449%3B1745111%3B8005717%3B6740443%3B8290811%3B9652289%3B279557%3B9077213%3B169933%3B4785463%3B368521%3B5881487%3B5735711%3B189377%3B3417091%3B8616299%3B7168723%3B4220969%3B4493651%3B5067977%3B1646387%3B3925297%3B5990723%3B6826471%3B3040753%3B1449733%3B8905681%3B2502001%3B7304107%3B1022677%3B4966529%3B8679397%3B4319519%3B3991279%3B1128641%3B2148631%3B2215987%3B1135217%3B3846281%3B1049843%3B309937%3B2241691%3B8768581%3B6199693%3B7973921%3B9683627%3B9664957%3B4493023%3B2494729%3B3581167%3B8474597%3B1987919%3B6099271%3B&t=68999&pxid=142221422
But I got in string:
?callback=ProxyApi.saveStat&cid=1343823765156_495&cidget=null&s[901]=1044!:!5878849%3B6658291%3B2964823%3B1178767%3B469747%3B481939%3B6431323%3B1032649%3B2750603%3B208057%3B9192763%3B6669071%3B2014351%3B6816157%3B3784367%3B1242929%3B4488073%3B7662331%3B2991731%3B6404357%3B8248091%3B1795603%3B4880191%3B3080303%3B4093847%3B4618063%3B7501937%3B2842849%3B6953249%3B7102679%3B5667853%3B9851873%3B5517823%3B6114539%3B6061597%3B7647599%3B4871873%3B400087%3B7514713%3B3958217%3B8163713%3B9560437%3B8229701%3B3408749%3B4432097%3B3353219%3B2936693%3B1343597%3B3490451%3B1266191%3B9125747%3B6152921%3B2689537%3B3796861%3B4987009%3B1206841%3B9278119%3B9499619%3B455627%3B6217051%3B7603201%3B8019079%3B5306033%3B8314939%3B2997221%3B3996221%3B3889649%3B1148507%3B9397139%3B4984949%3B6576473%3B3993247%3B676051%3B5%3B&s[902]=929!:!9012569%3B9836633%3B5239051%3B6102559%3B5944079%3B9749681%3B4007797%3B344821%3B9914917%3B1950227%3B982847%3B6610337%3B6734281%3B4213463%3B1620449%3B1745111%3B8005717%3B6740443%3B8290811%3B9652289%3B279
I lost some important data.
Im listing using:
IPAddress local_ip = Dns.GetHostAddresses(Dns.GetHostName())[0];
TcpListener sockServer = new TcpListener(local_ip,Port);
sockServer.Start();
And
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadFunction), sockServer.AcceptSocket());
And inside ThreadFunction I have
static void ThreadFunction(Object param)
{
Socket socket = (Socket)param;
proxy.Run(socket);
}
Finally I read message using this:
int bytes = ReadMessage(socket, readBuf, ref strFromClient);
Can you help me pass problem with URL LENGHT or change method of listining (unknown Javscript clients send large messeage using HTTP GET.)
===================
EDIT
I try using IE, Chrome and FF. I sent
http://172.16.210.25:8000/?callback=ProxyApi.saveStat&cid=1343823765156_495&cidget=null&s[901]=1044!:!5878849%3B6658291%3B2964823%3B1178767%3B469747%3B481939%3B6431323%3B1032649%3B2750603%3B208057%3B9192763%3B6669071%3B2014351%3B6816157%3B3784367%3B1242929%3B4488073%3B7662331%3B2991731%3B6404357%3B8248091%3B1795603%3B4880191%3B3080303%3B4093847%3B4618063%3B7501937%3B2842849%3B6953249%3B7102679%3B5667853%3B9851873%3B5517823%3B6114539%3B6061597%3B7647599%3B4871873%3B400087%3B7514713%3B3958217%3B8163713%3B9560437%3B8229701%3B3408749%3B4432097%3B3353219%3B2936693%3B1343597%3B3490451%3B1266191%3B9125747%3B6152921%3B2689537%3B3796861%3B4987009%3B1206841%3B9278119%3B9499619%3B455627%3B6217051%3B7603201%3B8019079%3B5306033%3B8314939%3B2997221%3B3996221%3B3889649%3B1148507%3B9397139%3B4984949%3B6576473%3B3993247%3B676051%3B5%3B&s[902]=929!:!9012569%3B9836633%3B5239051%3B6102559%3B5944079%3B9749681%3B4007797%3B344821%3B9914917%3B1950227%3B982847%3B6610337%3B6734281%3B4213463%3B1620449%3B1745111%3B8005717%3B6740443%3B8290811%3B9652289%3B279557%3B9077213%3B169933%3B4785463%3B368521%3B5881487%3B5735711%3B189377%3B3417091%3B8616299%3B7168723%3B4220969%3B4493651%3B5067977%3B1646387%3B3925297%3B5990723%3B6826471%3B3040753%3B1449733%3B8905681%3B2502001%3B7304107%3B1022677%3B4966529%3B8679397%3B4319519%3B3991279%3B1128641%3B2148631%3B2215987%3B1135217%3B3846281%3B1049843%3B309937%3B2241691%3B8768581%3B6199693%3B7973921%3B9683627%3B9664957%3B4493023%3B2494729%3B3581167%3B8474597%3B1987919%3B6099271%3B&t=68999&pxid=142221422
But I always get
GET /?callback=ProxyApi.saveStat&cid=1343823765156_495&cidget=null&s[901]=1044!:!5878849%3B6658291%3B2964823%3B1178767%3B469747%3B481939%3B6431323%3B1032649%3B2750603%3B208057%3B9192763%3B6669071%3B2014351%3B6816157%3B3784367%3B1242929%3B4488073%3B7662331%3B2991731%3B6404357%3B8248091%3B1795603%3B4880191%3B3080303%3B4093847%3B4618063%3B7501937%3B2842849%3B6953249%3B7102679%3B5667853%3B9851873%3B5517823%3B6114539%3B6061597%3B7647599%3B4871873%3B400087%3B7514713%3B3958217%3B8163713%3B9560437%3B8229701%3B3408749%3B4432097%3B3353219%3B2936693%3B1343597%3B3490451%3B1266191%3B9125747%3B6152921%3B2689537%3B3796861%3B4987009%3B1206841%3B9278119%3B9499619%3B455627%3B6217051%3B7603201%3B8019079%3B5306033%3B8314939%3B2997221%3B3996221%3B3889649%3B1148507%3B9397139%3B4984949%3B6576473%3B3993247%3B676051%3B5%3B&s[902]=929!:!9012569%3B9836633%3B5239051%3B6102559%3B5944079%3B9749681%3B4007797%3B344821%3B9914917%3B1950227%3B982847%3B6610337%3B6734281%3B4213463%3B1620449%3B1745111%3B8005717%3B6740443%3B8290811%3B9652289%3B279
Look
private Byte[] readBuf = new Byte[2048];
int bytes = ReadMessage(socket, readBuf, ref strFromClient);
My bytes always are to 1024. Where can be limits of there?
HTTP GET requests are usually limited to ~2000 characters (client-wise, that is)
Here's a reference from MS
GET is not intended for sending large amount of data, that's why it's called GET... try to provide more information regarding your client and we might be able to offer you an alternative
I was careless.
Function ReadMessage is function from own class. And it wrote:
sock.Receive(buf, 1024, 0);
Of course I fix:
sock.Receive(buf,buf.Length,0);
And Now it runs.
Thank for your answers.
I'm trying to send a broadcast UDP message to a C# application. I have tried the following code to send the message. Which I found on the php.net website as a comment to the socket_sendto manual page.
<?php
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_set_option($sock, SOL_SOCKET, SO_BROADCAST, 1);
socket_sendto($sock, $broadcast_string, strlen($broadcast_string), 0, '255.255.255.255', $port);
?>
This doesn't work for me, maybe it's my network.
But it does work if I replace the broadcast IP '255.255.255.255' to my specific IP e.g. '192.168.1.128'. I can see this message coming in with Wireshark, while I can't see this using the above code. This leads me to believe there is something wrong with the PHP side of the code. I really want to use broadcasting or some kind of multicasting for my program, so I'm a bit stuck at the moment ;)
I use the following on the (C#) receiving end (for testing):
UdpClient subscriber = new UdpClient(15000);
IPEndPoint ep = new IPEndPoint(IPAddress.Any, 15000); ;
byte[] pdata = subscriber.Receive(ref ep);
string data = Encoding.ASCII.GetString(pdata);
MessageBox.Show(data);
subscriber.Close();
Any idea what could be the cause of this?
Try specifying the MSG_DONTROUTE flag in your script. Taking inspiration from this CodeGuru post, if this isn't specified the routers make the decision on whether or not to broadcast your message.
socket_sendto($sock, $broadcast_string, strlen($broadcast_string), MSG_DONTROUTE, '255.255.255.255', $port);
255.255.255.255 is a "limited" broadcast whereas your 192.168.1.255 is a "directed" broadcast.
Limited in simple terms means that it is only send within the LAN. LAN as defined by directly connected hosts, i.e. with no router in between. Routers--with a few exceptions--do not pass a limited broadcast but a directed broadcast.
Now, with your initial problem and question, I can only guess that you are sending your broadcast across a router.
I am writing two console applications, a client and a server.
I'm a little stuck at two things, which seemed rather easy at first..
#1: I want to write a function for the following piece of code, that converts bits to a string, but I cant just figure it out. The server always crashes when I use it. My function is a little bit different than this one, but that's because my current code has to include the connection information, and I think there's a better way to do it:
byte[] b = new byte[100];
int k = s.Receive(b);
string packet = null;
for (int i = 0; i < k; i++)
{
Console.Write(Convert.ToChar(b[i]));
packet = packet + Convert.ToChar(b[i]);
}
I guess the function is not the problem, but how I use it is. Any help would be very much apreciated.
Edit:
I am calling and using it like this:
byte[] b = new byte[100];
string response = BitConvert(b);
if (response == "Hi there")
#2 I want the client to álways send a packet just once, with a password. And if that password doesn't match the password mentioned as a string in the server, it should close the connection with the client.
I know how to send the packet just once, but I don't know how to check the packet in the server just once for each client.
Or in other words, at the moment the server has no way of knowing if the client has already been authenticated. So I guess the client needs to have some sort of socket ID, and the server needs a table with the ID, and a boolean to see if it's autenticated or not.
The first part, getting the bytes into a string ... how about:
byte b[] = new byte[100];
int k = s.Receive(b, b.Length, 0);
string packet = Encoding.ASCII.getString(b, 0, k);
Part 2 ... not sure off the top of my head.
I'm with Rob above on part 1 and as for part 2...
Assuming you're using a TCP connection the System.Net.Sockets class should handle your
needs.
If you use either AcceptSocket or AcceptTcpClient to pull a connection from the incoming connection request queue you'll get a socket or tcpclient that is unique to that connection. simply leave it open until you're done with it. (There are also non-blocking alternatives if your service has other things to do...)
If the client closes it or opens up a new connection the will have to reauthenticate somehow. (This may be by including a token that you generate for them when they first authenticate - that's your only option if you're using UDP connections).
I'm writing an application to send data over a network, and need to know if it is possible to set the Type of Service (ToS) bits in the IP Packet header. Anyone know if this is supported by C#, and if so how I should go about implementing it?
I know I can use a raw socket type and specify my own header, but I'd rather not have to do this as I'm only using TCP, so it seems a bit pointless to create an entire header just so I can set three bits, when it can be automatically created without these bits set.
Any suggestions would be greatly appreciated.
Wouldn't this work? (almost straight from TcpClient.Client help)
TcpClient client = new TcpClient();
Socket s = client.Client;
if (!s.Connected)
{
s.SetSocketOption(SocketOptionLevel.IP,
SocketOptionName.TypeOfService, 2);
}
Not sure what value you want to set it to, but this should work...