C# smart cards serial intrface - c#

Have a trouble with smart card reader. Reader is connect to pc through Usb-to-Serial converter. Can't read anything from reader.
...
static void Main(string[] args)
{
byte[] data = new byte[256];
byte[] recived = new byte[256];
data[0] = 0x00;
data[1] = 0xA4;
data[2] = 0x04;
data[3] = 0x00;
data[4] = 0x00;
data[5] = 0x00;
data[6] = 0x00;
System.IO.Ports.SerialPort sp = new System.IO.Ports.SerialPort("COM4", 38400, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One);
sp.WriteTimeout = 300;
sp.ReadTimeout = 300;
sp.DataReceived += Sp_DataReceived;
sp.ErrorReceived += Sp_ErrorReceived;
if (sp.IsOpen)
{sp.Close();}
sp.Open();
try {
sp.Write(data, 0, 7);
int bt = sp.ReceivedBytesThreshold;
sp.Read(recived, 0, bt);
if (bt != 0)
{ Console.WriteLine(bt.ToString());
Console.ReadKey();}
} catch (Exception ex){
Console.WriteLine(ex.Message);
Console.ReadKey();}
}
private static void Sp_ErrorReceived(object sender, System.IO.Ports.SerialErrorReceivedEventArgs e)
{Console.ReadKey();}
private static void Sp_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{Console.ReadKey();}
}
}
Code doesn't do anything as if there isn't card reader in the system.

Well, first of all you're attaching the event handlers after you send something to the reader. That's not good. I recommend initializing the SerialPort instance completely (set it up, attach events, etc) and only after that, open the connection and communicate.
Also your application doesn't wait for anything. If you use the asynchronous communication (by defining the DataReceived event) you need to make sure your application actually loops and waits.
Your console application doesn't do that. It writes something to the serial port and then quits as it steps out of the Main method. If you expect an answer you need to decide:
Use the synchronous way calling the methods to actually block/read from the serial port.
Use the asynchronous way as you started doing, but then make your application run without blocking any threads.
And please: Don't mix the two! I see a lot of code where people in DataReceived write a loop because they don't get all the information in one go. Don't do that. Instead build a buffer and check it for complete transmissions. No Read in DataReceived!
The following code might work. It will not implement the asynchronous variant, but the blocking, synchronous approach:
static void Main(string[] args)
{
byte[] data = new byte[256];
byte[] recived = new byte[256];
data[0] = 0x00;
data[1] = 0xA4;
data[2] = 0x04;
data[3] = 0x00;
data[4] = 0x00;
data[5] = 0x00;
data[6] = 0x00;
using (System.IO.Ports.SerialPort sp = new System.IO.Ports.SerialPort("COM4", 38400, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One))
{
try
{
sp.Open();
sp.Write(data, 0, 7);
int bytesRead = sp.Read(recived, 0, received.Length);
if (bytesRead != 0)
{
string s = Encoding.ASCII.GetString(received, 0, bytesRead);
Console.WriteLine(s);
Console.ReadKey();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadKey();
}
}
}
If that doesn't show any result on the console, then there might be several causes of error, including:
Wrong COM configuration (is BAUD rate, etc. correct?)
Wrong serial port (do you have more than one?)
Device doesn't communicate the way you think (are you sending the correct command?)
etc..

Related

Serial port ReadByte() time out exception

I am working on a C# application. My application has to do serial communication with a hardware device. The device is connected with my system on "COM4" com port. Code:
serialPort = new SerialPort("COM4", 2400, Parity.Odd, 8, StopBits.One);
serialPort.WriteTimeout = 5000;
serialPort.ReadTimeout = 5000;
serialPort.Open();
serialPort.Handshake = Handshake.None;
serialPort.DtrEnable = true;
serialPort.RtsEnable = true;
After that i do a write operation, this works fine. Code:
private void WriteMessage(byte[] busMsg)
{
BinaryWriter writer = new BinaryWriter(serialPort.BaseStream);
writer.Write(busMsg);
writer.Flush();
}
After write, when i do ReadByte operation, i get the timeout exception. Code:
private byte ReadAEBusMessageResponse()
{
BinaryReader reader = new BinaryReader(serialPort.BaseStream);
return reader.ReadByte();
}
I read somewhere on google that BaseStream might cause issue, so i tried the below code for reading but, still no luck and i am still getting the timeout exception.
private byte ReadAEBusMessageResponse()
{
SerialPort currentPort = serialPort;
return Convert.ToByte(currentPort.ReadByte());
}
I do get the response when i try communication with Hercules, so i assume there is no issue with response from device. What am i doing wrong with serial communication ? any help would be much appreciated.
I have only found the async event to work. I have created my own byte receive buffer and then I handle the event:
static byte[] RXbuffer = new byte[512]; //"static" so it can be used all over
public void SerialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
Byte_Size = SerialPort.BytesToRead;
SerialPort.Read(RXbuffer, 0, Byte_Size);
/* Return to UI thread */
this.Invoke(new EventHandler(DisplayText));
}
the DisplayText is a method to print the buffer in a textbox.
private void DisplayText(object sender, EventArgs e)
{
int i = 0;
byte[] Received_Bytes = new byte[Byte_Size];
while (i < Byte_Size)
{
Received_Bytes[i] = RXbuffer[i];
i++;
}
TB_Info.AppendText("\r\nBytes Received: ");
TB_Info.AppendText(Byte_Size.ToString());
TB_Info.AppendText("\r\n--> ");
TB_Info.AppendText(BitConverter.ToString(Received_Bytes));
TB_Info.AppendText("\r\n");
//Array.Copy(RXbuffer,Full_RX_Buff,)
}
You can then read/manipulate the values later.
***Don't forget that in the SerialPort object that put on your form, you have to go into the properties/events dialog and assign the function that handles the receivedata event!

Sending data to a TCP Server

I'm trying to realize a program that sends data to a TCP-server and then receives the same message by COM-port. I have the following code but it sends the data but doesn't receive any data.
When I monitor the serial port I can't see that the data is received.
How do I fix this? Do I have to switch to a multi threading system or is there a other way to sync this? Because I can see that the COM-port is opened but not read out.
And when I test this with Putty I can get it to work.
public class Variables
{
private static int v_VarI = 0;
public static int VarI
{
get { return v_VarI; }
set { v_VarI = value; }
}
private static int v_VarJ = 0;
public static int VarJ
{
get { return v_VarJ; }
set { v_VarJ = value; }
}
}
class Program
{
public class TcpTimeClient
{
private const int portNum = 6666;
private const string hostName = "192.168.1.51";
private const string data = "test";
public static int Main(String[] args)
{
new SerialPortProgram();
while (Variables.VarI < 10)
{
Byte[] bytesSent = Encoding.ASCII.GetBytes(data);
try
{
TcpClient client = new TcpClient(hostName, portNum);
NetworkStream ns = client.GetStream();
byte[] bytes = new byte[1024];
ns.Write(bytesSent, 0, bytesSent.Length);
int bytesRead = ns.Read(bytes, 0, bytes.Length);
client.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Variables.VarI++;
while (Variables.VarJ < Variables.VarI)
{
}
}
Console.ReadLine();
return 0;
}
}
public class SerialPortProgram
{
public SerialPort receiveport = new SerialPort("COM3", 115200, Parity.None, 8, StopBits.One);
public SerialPortProgram()
{
receiveport.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
receiveport.Open();
}
public void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// Show all the incoming data in the port's buffer
string rec_data = receiveport.ReadExisting();
Console.WriteLine(rec_data);
Variables.VarJ++;
}
}
}
Update
I've found that the program I wrote and putty and an other program named Serial Port Monitor differ in the IOCTL_SERIAL_SET_WAIT_MASK.
Serial Port Monitor: 0x00 00 01 19
Putty: Unkown
Own program: 0x00 00 01 FB
Does anyone know how to change this mask? Because it's not in the System.IO.Ports.SerialPort class.
you can use this :
public void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int length = receiveport.BytesToRead;
byte[] buf = new byte[length];
SerialPort2.Read(buf, 0, length);
}
buf array is your answer but in decimal mode . and you can changed it to want.
The wait mask is not your problem. Your wait mask enables the serial port for RXCHAR RXFLAG CTS DSR RLSD BRK ERR RING and has everything except ERR turned on.
This is correct for the way .Net wraps serial ports, and anyway it is not exposed in the .NET serial port class. Don't waste time pursuing that difference; your problem lies elsewhere.
Your serial port code ran perfectly on my system and printed all the data received from an external serial source, so I suspect your problem is with the TCP server whose code you did not post, or with your serial ports. Perhaps your configuration requires that you transmit something before the port begins sending? Try something like:
receiveport.Open();
receiveport.WriteLine("?");
Then if you still have problems, try connecting to another serial device to see if you can prove your receive code is working for you as it is for me. If you still can't figure it out, post more information about what's happening on the serial source end.

C# sockets: can't read after writing to socket

In my client/server application my client wiil communicate with the server for 2 functions: the client will either request data from the server or it will send data so the server will save it. I'm using one socket for both methods, and the method to be used is defined by the first byte sent. If the first byte is "1" it is requesting data. If it is "2", it will send data (data bytes are sent after the "2" byte). It works perfectly for sending data. But when I'm requesting data it works, as long as I don't read the socket stream in the client. It's like if I make the client read data after sending data, the server will have no data to read, and it just crashes when trying to read the data.
Here is my server code:
private const int BufferSize = 1024;
NetworkStream netstream = null;
byte[] RecData = new byte[BufferSize];
int RecBytes;
try {
netstream = clientSocket.GetStream();
int totalrecbytes = 0;
using (MemoryStream ms = new MemoryStream()) {
//When I get here, there is no data to read
while ((RecBytes = netstream.Read(RecData, 0, RecData.Length)) > 0) {
ms.Write(RecData, 0, RecBytes);
totalrecbytes += RecBytes;
}
byte[] bytes = ms.ToArray();
byte b = bytes[0];
switch (b) {
case 1:
//Here I gather data and put it in "stream" variable
byte[] SendingBuffer = null;
int NoOfPackets = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(stream.Length) / Convert.ToDouble(BufferSize)));
int TotalLength = (int)stream.Length, CurrentPacketLength, counter = 0;
for (int i = 0; i < NoOfPackets; i++) {
if (TotalLength > BufferSize) {
CurrentPacketLength = BufferSize;
TotalLength = TotalLength - CurrentPacketLength;
}
else
CurrentPacketLength = TotalLength;
SendingBuffer = new byte[CurrentPacketLength];
stream.Read(SendingBuffer, 0, CurrentPacketLength);
netstream.Write(SendingBuffer, 0, (int)SendingBuffer.Length);
}
netstream.Flush();
}
catch (Exception e) {
Console.WriteLine("EXCEPTION:\n" + e.ToString());
}
break;
case 2:
//Code to read data
break;
}
}
netstream.Close()
clientSocket.Close();
And here is my client code:
using (System.Net.Sockets.TcpClient clientSocket = new System.Net.Sockets.TcpClient()) {
string returnData = "";
IAsyncResult ar = clientSocket.BeginConnect("127.0.0.1", 8080, null, null);
System.Threading.WaitHandle wh = ar.AsyncWaitHandle;
try {
if (!ar.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5), false)) {
clientSocket.Close();
Console.WriteLine("Timeout");
return;
}
System.Net.Sockets.NetworkStream serverStream = clientSocket.GetStream();
byte b = 1;
byte[] outStream = { b };
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
//If I comment following lines, the server can read sent data, but server can't otherwise
byte[] RecData = new byte[1024];
int RecBytes;
int totalrecbytes = 0;
MemoryStream MS = new MemoryStream();
while ((RecBytes = serverStream.Read(RecData, 0, RecData.Length)) > 0) {
MS.Write(RecData, 0, RecBytes);
totalrecbytes += RecBytes;
}
serverStream.Close();
clientSocket.Close();
clientSocket.EndConnect(ar);
}
catch (Exception ex) {
Console.WriteLine("Exceção: " + ex.ToString());
}
finally {
wh.Close();
}
}
So, how can I send data to server and read the response? (I tried even putting the thread to sleep after sending data, with no luck.)
Thanks in advance.
EDIT:
With some debug messages I discovered that the server do read the "1" byte that was sent, but somehow it gets stuck inside the while loop, like, the server just stops there, no more loops and it does not leave the while loop. I saw that after writing "loop" in console inside the while loop, and writing read bytes also in console. It wrote "loop" once, and the read byte.
This code worries me:
//When I get here, there is no data to read
while ((RecBytes = netstream.Read(RecData, 0, RecData.Length)) > 0) {
ms.Write(RecData, 0, RecBytes);
totalrecbytes += RecBytes;
}
You are reading until the client closes the connection (or shuts down sending, which you don't do). But the client only closes when the server has replied. The server reply will never come. It is a deadlock.
Solution: Read a single byte to determine the requests command (b).
Unrelated to the question, your "packetised" sending (NoOfPackets, ...) does not seem to serve any purpose. Just use Stream.Copy to write. TCP does not have packets.
An even better solution would be to abandon your custom TCP protocol and use an HTTP library. All these concerns just go away. There are various smaller problems with your code that are very typical to see in TCP code.

Sending message from C# client to C server

I'm fairly new to socket programming, but, using an online tutorial, I've successfully sent a short string from one machine to another using C.
The problem I'm having is with trying to send a string from a client written in C#. The server (written in C) prints out a blank/empty string.
Here is the C code that runs on the "server" machine (in this case a router running OpenWRT):
int main(int argc, char *argv[])
{
int listenfd = 0, connfd = 0;
struct sockaddr_in serv_addr;
char recvBuff[1025];
int bytesRead;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(1234);
bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
printf("Listening for string on port 1234...\n");
listen(listenfd, 10);
while(1)
{
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
bytesRead = recv(connfd, recvBuff, 1024, 0); // Receive string
if (bytesRead < 0)
{
printf("Error reading from stream\n");
}
recvBuff[bytesRead] = 0; // null-terminate the string
printf("%d:%s\n", bytesRead, recvBuff);
close(connfd);
sleep(1);
}
}
When sending this little server a string from another C program it works exactly as expected (prints the string out then waits for another one). [Note: I don't think the C client's code is relevant, but I can post it if need be]
However, when trying to send it a string from a C# program (copied below), the server prints out 0: (i.e. 0 bytes read, followed by an empty string) and I can't for the life of me figure out what the issue is. Both apps are pretty straightforward, so I'm assuming I should be using something other than WriteLine (I've also tried Write but to no avail).
C# Client:
namespace SocketTest
{
class Program
{
static void Main(string[] args)
{
TcpClient client = new TcpClient("10.45.13.220", 1234);
Stream stream = client.GetStream();
StreamWriter writer = new StreamWriter(stream);
writer.WriteLine("Testing...");
client.Close();
}
}
}
To null terminate a string use
recvBuff[bytesRead] = '\0';
And call close on writer (which causes the writer to flush any pending bytes)
writer.WriteLine("Testing...");
writer.Close();
client.Close();

File Transfer using sockets and multiple clients

I have a large application written using .Net remoting for file transfer. This was borking in some circumstances with the sockets being forcibly closed - I wasn't using sockets directly, but a .Net remoting call with byte arrays (I wasn't sending the whole file in one transfer, I was splitting it up).
So, I decided to change the actual file transfer part to use sockets.
As a proof of concept, to see if I got the principles right, I have written a simple console client and a server.
I am using ASynch recieves but synchronous writes - I have tried with both being ASync but same reseult, and keeping it synchronous made debugging easier.
What the apps do (code below) is the server sits and waits for files to be transfered, and it stores them in a directory at a given name.
When enter is pressed, the server then reads the files recieved and sends them back to the clients who store them under a different name. I wanted to test file transfer both ways.
Using one instance of the client application, all is well - the server recieves it and then sends it back to the client. All is well. Yes, the client throws an exception when you terminate the server - but that is fine - I know that the socket was forcibly closed...I can deal with tidying upu the code when it is working.
However, when I create 2 instances of the client code (not forgetting to modify the code slightly to read a different file to send, and also to store the received file under a different name) - the server receives both files from the clients, sends the first one back just fine, and then a few segments into the second file it throws with a "non blocking socket operation could not be completed immediatly" - which is odd because nothing is blocking, and the recieves are async - and the sends are actually blocking!
Any suggestions please as to what I am doing wrong - no doubt it is something stupid, but still...
The aim of the final code is to be able to have n clients contact the server and send files to it, and also, at random intervals have the server send 1 or more files back to some/all of the clients.
Cheers folks!
Server code
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.IO;
namespace SocketServer
{
class ConnectionInfo
{
public Socket Socket;
public byte[] Buffer;
public int client;
}
class Program
{
static int chunkSize = 16 * 1024;
static int chucksizeWithoutHeaderData = chunkSize - 8;
static List<ConnectionInfo> list = new List<ConnectionInfo>();
static Socket serverSocket;
static int nClient = 0;
static void AcceptCallback(IAsyncResult result)
{
ConnectionInfo info = new ConnectionInfo();
info.Socket = serverSocket.EndAccept(result);
info.Buffer = new byte[chunkSize];
Console.WriteLine("Client connected");
nClient++;
info.client = nClient;
list.Add(info);
info.Socket.BeginReceive(info.Buffer,0,info.Buffer.Length,SocketFlags.None, new AsyncCallback(ReceiveCallBack), info);
serverSocket.BeginAccept(new AsyncCallback(AcceptCallback),null);
}
static void ReceiveCallBack(IAsyncResult result)
{
ConnectionInfo info = result.AsyncState as ConnectionInfo;
try
{
Int32 nSegmentNumber = BitConverter.ToInt32(info.Buffer,0);
Int32 nMaxSegment = BitConverter.ToInt32(info.Buffer,4);
string strFileName = string.Format(#"c:\temp\from-client-{0}.dat",info.client);
int bySize = info.Socket.EndReceive(result);
using (FileStream fs = new FileStream(strFileName, FileMode.OpenOrCreate))
{
Console.WriteLine("Received segment {0} of {1} from client {2}", nSegmentNumber, nMaxSegment, info.client);
fs.Position = fs.Length;
fs.Write(info.Buffer, 8, bySize-8);
if (nSegmentNumber >= nMaxSegment)
{
Console.WriteLine("Completed receipt from client {0}", info.client);
}
}
info.Socket.BeginReceive(info.Buffer, 0, info.Buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), info);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
static void Main(string[] args)
{
try
{
Console.WriteLine("Server");
IPAddress address = IPAddress.Parse("127.0.0.1"); //The IP address of the server
IPEndPoint myEndPoint = new IPEndPoint(address, 6503);
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(myEndPoint);
serverSocket.Listen(1000);
for (int n = 0; n < 10; ++n)
{
serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
Console.WriteLine("Server now waiting");
Console.ReadLine();
foreach (ConnectionInfo info in list)
{
string strFileName = string.Format(#"c:\temp\from-client-{0}.dat", info.client);
using (FileStream fs = new FileStream(strFileName, FileMode.Open, FileAccess.Read, FileShare.None))
{
int nMaxChunk = 0;
int nCurrentChunk = 0;
nMaxChunk = (int)(fs.Length / chucksizeWithoutHeaderData);
if ((nMaxChunk * chucksizeWithoutHeaderData) < fs.Length)
{
++nMaxChunk;
}
using (BinaryReader br = new BinaryReader(fs))
{
byte[] byBuffer;
Int64 nAmount = 0;
byte[] byMaxChunk = BitConverter.GetBytes(nMaxChunk);
while (fs.Length > nAmount)
{
++nCurrentChunk;
byte[] byCurrentChunk = BitConverter.GetBytes(nCurrentChunk);
byBuffer = br.ReadBytes(chucksizeWithoutHeaderData);
Console.WriteLine("Sending {0}bytes, chunk {1} of {2} to client {3}", byBuffer.Length,nCurrentChunk,nMaxChunk, info.client);
byte [] byTransmitBuffer = new byte[byBuffer.Length + 8];
Array.Copy(byCurrentChunk, byTransmitBuffer, 4);
Array.Copy(byMaxChunk, 0,byTransmitBuffer, 4, 4);
Array.Copy(byBuffer, 0, byTransmitBuffer, 8, byBuffer.Length);
info.Socket.Send(byTransmitBuffer);
nAmount += byBuffer.Length;
}
}
}
}
Console.WriteLine("Press enter to end server");
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex);
Console.ReadLine();
}
}
}
}
Client code
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.IO;
using System.Threading;
namespace SocketClient
{
class Program
{
static TcpClient socket = new TcpClient();
static int chunkSize = 16 * 1024;
static int chucksizeWithoutHeaderData = chunkSize - 8;
static byte[] byReceiveBuffer = new byte[chunkSize];
static void ReceiveCallBack(IAsyncResult result)
{
Socket socket = result.AsyncState as Socket;
try
{
int bySize = socket.EndReceive(result);
Console.WriteLine("Recieved bytes {0}", bySize);
if (bySize != 0)
{
Int32 nSegmentNumber = BitConverter.ToInt32(byReceiveBuffer, 0);
Int32 nMaxSegment = BitConverter.ToInt32(byReceiveBuffer, 4);
Console.WriteLine("Received segment {0} of {1}", nSegmentNumber, nMaxSegment);
string strFileName = string.Format(#"c:\temp\client-from-server.dat");
using (FileStream fs = new FileStream(strFileName, FileMode.OpenOrCreate))
{
fs.Position = fs.Length;
fs.Write(byReceiveBuffer, 8, bySize-8);
}
if (nSegmentNumber >= nMaxSegment)
{
Console.WriteLine("all done");
}
}
socket.BeginReceive(byReceiveBuffer, 0, byReceiveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), socket);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
static void Main(string[] args)
{
Console.WriteLine("Press enter to go");
Console.ReadLine();
socket.Connect("127.0.0.1", 6503);
Console.WriteLine("Client");
Console.ReadLine();
byte[] byBuffer;
socket.Client.BeginReceive(byReceiveBuffer, 0, byReceiveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), socket.Client);
using (FileStream fs = new FileStream(#"c:\temp\filetosend.jpg", FileMode.Open, FileAccess.Read, FileShare.None))
{
using (BinaryReader br = new BinaryReader(fs))
{
int nMaxChunk = 0;
int nCurrentChunk = 0;
nMaxChunk = (int)(fs.Length / chucksizeWithoutHeaderData);
if ((nMaxChunk * chucksizeWithoutHeaderData) < fs.Length)
{
++nMaxChunk;
}
byte[] byMaxChunk = BitConverter.GetBytes(nMaxChunk);
Int64 nAmount = 0;
while (fs.Length > nAmount)
{
++nCurrentChunk;
byte[] byCurrentChunk = BitConverter.GetBytes(nCurrentChunk);
byBuffer = br.ReadBytes(chucksizeWithoutHeaderData);
Console.WriteLine("Sending {0}bytes, chunk {1} of {2}", byBuffer.Length, nCurrentChunk, nMaxChunk);
byte[] byTransmitBuffer = new byte[byBuffer.Length + 8];
Array.Copy(byCurrentChunk, byTransmitBuffer, 4);
Array.Copy(byMaxChunk, 0, byTransmitBuffer, 4, 4);
Array.Copy(byBuffer, 0, byTransmitBuffer, 8, byBuffer.Length);
socket.Client.Send(byTransmitBuffer);
nAmount += byBuffer.Length;
}
}
}
Console.WriteLine("done");
Console.ReadLine();
}
}
}
Since you are modifyng the infrastructure, use an FTP library in C# and install some free FTP server ( ie FileZilla or anyone else ). You can easily use some FTP library as for example this one that is reliable ( i used it on production code ).
Socket programming can be tricky. If you send 100 bytes, it doesn't mean you will receive 100 bytes in your server. You can receive those 100 bytes in multiple packets, you have to add code to control that.
I said that because of this line in your server code:
fs.Write(info.Buffer, 8, bySize-8);
you are assuming you will receive at least 8 bits and it can be wrong. bySize can be smaller than your chunk size (and it can be zero if the connection has been closed by the client or <0 if there was an error.)
About your error, I tested your code and I could replicate your problem:
start the server
start the client and transfer the file
exit the client pressing enter
the server crashes
The server crashes because the socket is waiting for more data after all the file is transferred. And the client closed it.
I solved the problem closing the connection in the client after the file is sent:
socket.Client.Disconnect(false);
Then the server receives bySize=0 bytes, meaning that the connection was closed. In the server I replaced this:
int bySize = socket.EndReceive(result);
for this:
int bySize = 0;
try
{
bySize = info.Socket.EndReceive(result);
}
catch (Exception ex)
{
Console.WriteLine("Error from client {0}: {1}", info.client, ex.Message);
return;
}
if (bySize <= 0)
return;
Have a look here: http://msdn.microsoft.com/en-us/library/5w7b7x5f.aspx#Y240
and here: http://msdn.microsoft.com/en-us/library/fx6588te.aspx
EDIT: I forgot to mention this, you only need to call BeginAccept once. I removed the for statement.
// for (int n = 0; n < 10; ++n)
// {
serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
// }
I think that I may have a solution - although I am not 100% confident...I will keep testing and report back if it fails.
Anyways - I have set the socket.SendBufferSize and RecieveBufferSize to 4 x the chunk size, and now all seems to be well.
The thing there (re buffer size) just put the problem off, as I thought it might.
However, I came across a snippet of code elsewhere, and putting these lines into the code fixed the issue.
try
{
bySent = info.Socket.Send(byTransmitBuffer);
}
catch (SocketException ex)
{
Console.WriteLine("Only sent {0}, remaining = {1}", bySent,fs.Length -nAmount);
if (ex.SocketErrorCode == SocketError.WouldBlock ||
ex.SocketErrorCode == SocketError.IOPending ||
ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
{
// socket buffer is probably full, wait and try again
Thread.Sleep(30);
}
else
throw ex; // any serious error occurr
}

Categories