Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
353 views
in Technique[技术] by (71.8m points)

c# - Specified argument was out of the range of valid values. Parameter name: size & Serial Port Communication

I need to create an application which requires communicating to an existent software using TCP/IP, where both mine and the other application will be using the port number specified below.

private void frmScan_Load(object sender, EventArgs e)
{
    clientSocket.Connect("100.100.100.30", 76545);
}

public void msg(string mesg)
{
    textBox1.Text = textBox1.Text + Environment.NewLine + " >> " + mesg;
}

private void cmdSCANok_Click(object sender, EventArgs e)
{

    msg("Client Started");
    NetworkStream serverStream = clientSocket.GetStream();
    byte[] outStream = Encoding.ASCII.GetBytes("PCK|SCAN|5025066840471");

    serverStream.Write(outStream, 0, outStream.Length);
    serverStream.Flush();

    byte[] inStream = new byte[10025];
    serverStream.Read(inStream, 0, (int)clientSocket.ReceiveBufferSize);
    string returndata = Encoding.ASCII.GetString(inStream, 0, inStream.Length);


    msg("Data from Server : " + returndata);
} 

What happens is, the program I am communicating with has some in-built language where it will understand the code that I send, and it will return data according to the code that I have sent. So in the code above, I sent three bits of code: ("PCK|SCAN|5025066840471") which will find a specific item in the database. When it runs, I get an error on the line:

serverStream.Read(inStream, 0, (int)clientSocket.ReceiveBufferSize);

the error shows the following: "Specified argument was out of the range of valid values. Parameter name: size"

I followed the tutorial I saw on this website: http://csharp.net-informations.com/communications/csharp-client-socket.htm - But I did slightly different. So instead of putting

string returndata = Encoding.ASCII.GetString(inStream);

I wrote:

string returndata = Encoding.ASCII.GetString(inStream, 0, inStream.Length); 

I am extremely confused on why I am getting those problems, and to be honest I am not understanding much of what the code is doing, I just have a rough idea, but not enough to troubleshoot this. Can someone help please?

Much appreciated!

PS: I am programming for Windows CE (portable device) on Visual Studio 2010.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Your code is a great example of how not to do TCP communication. I've seen this code copied over and over many times, and I'd be very happy to point you to a good tutorial on TCP - too bad I haven't seen one yet :)

Let me point out some errors first:

  • TCP doesn't guarantee you the packet arrives as one bunch of bytes. So (theoretically) the Write operation could result in a split, requiring two reads on the other side. Sending data without headers over TCP is a very bad idea - the receiving side has no idea how much it has to read. So you've got two options - either write the length of the whole bunch of data before the data itself, or use a control character to end the "packet"
  • The first point should also clarify that your reading is wrong as well. It may take more than a single read operation to read the whole "command", or a single read operation might give you two commands at once!
  • You're reading ReceiveBufferSize bytes into a 10025 long buffer. ReceiveBufferSize might be bigger than your buffer. Don't do that - read a max count of inStream.Length. If you were coding in C++, this would be a great example of a buffer overflow.
  • As you're converting the data to a string, you're expecting the whole buffer is full. That's most likely not the case. Instead, you have to store the return value of the read call - it tells you how many bytes were actually read. Otherwise, you're reading garbage, and basically having another buffer overflow.

So a much better (though still far from perfect) implementation would be like this:

NetworkStream serverStream = clientSocket.GetStream();
byte[] outStream = Encoding.ASCII.GetBytes("PCK|SCAN|5025066840471");

// It would be much nicer to send a terminator or data length first, 
// but if your server doesn't expect that, you're out of luck.
serverStream.Write(outStream, 0, outStream.Length);

// When using magic numbers, at least use nice ones :)
byte[] inStream = new byte[4096];

// This will read at most inStream.Length bytes - it can be less, and it
// doesn't tell us how much data there is left for reading.
int bytesRead = serverStream.Read(inStream, 0, inStream.Length);

// Only convert bytesRead bytes - the rest is garbage
string returndata = Encoding.ASCII.GetString(inStream, 0, bytesRead);

Oh, and I have to recommend this essay on TCP protocol design.

It talks about many of the misconceptions about TCP, most importantly see the Message Framing part.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...