ftp - Identify an incoming file through NetworkStream C# -
i making client/server chat application using tcpclient , tcplistener classes. should able transfer text messages , files between client , server. able handle text messages making thread each separate client , making secondary thread receiving incoming message making primary thread reserved sending messages. if able identify incoming message file , not text message know how handle using networkstream , filestream. unable so. code handle incoming file here. please tell me if there limitations using networkstream ftp.
answer: build own protocol.
by building own communication protocol can control data/message flow.
for example;
1-user wants send file server
2-client sends command inform server send file.like ;
@file@filename;filesize;
3-server sends ready message client @fileaccepted@
4-server begins listen buffer packages , when receives writes them stream.
5-when client receives {@fileaccepted@}
command begins send packages server. sure buffer sizes same.
6-when bytes complete client sends @fileend@
in diffrent buffer (i use 256 commands , 1024 file transfer)
7-when server receives 256 byte command looks if @fileend@
command , true flushes file stream , closes connection.
i recomment use async
listen connections on server
server.beginaccepttcpclient(serveracceptend,server);
and when connection present
public void serveracceptend(iasyncresult ar) { if(!ar.iscompleted) { //something went wrong acceptserver(); return; } try { var cli = servertc.endaccepttcpclient(ar); if(cli.connected) { //get first command cli.getstream().beginread(serverredbuffer,0,serverredbuffer.length,serverfirstreadend,cli); } else { //connection not successfull log , wait acceptserver(); } } catch(exceiption ex) { //an error occur log , wait new connections acceptserver(); } }
when first command received ;
public void serverfirstreadend(iasyncresult ar) { if(!ar.iscompleted) { //something went wrong acceptserver(); return; } try { tcpclient cli = (tcpclient)ar.asyncstate; int read = cli.getstream().endread(ar); string req = tostring(serverredbuffer); if(req.startswith("@file@")) { //file received string filename = req.replace("@file@",""); string[] spp = filename.split(';'); filename = spp[0]; serverreceivetotalbytes = convert.toint64(spp[1]); cli.getstream().write(tobyte("@fileaccepted@",256),0,256); cli.getstream().beginread(serverreceivebuffer,0,1024,serverreadfilecyle,cli) } else { //message received } } catch(exception ex) { //an error occur log , wait new connections acceptserver(); } }
file receive method ;
public void serverreadfilecyle(iasyncresult ar) { tcpclient cli = (tcpclient)ar.asyncstate; if(ar.iscompleted) { int read = cli.getstream().endread(ar); if(read == 256) { try { string res = tostring(serverreceivebuffer); if(res == "@fileend@") read = 0; } catch { } } if(read > 0) { serverfile.write(serverreceivebuffer,0,read); cli.getstream().beginread(serverreceivebuffer,0,1024,serverreadfilecyle,cli); } else { serverfile.flush(); serverfile.dispose(); acceptserver(); } } }
this part server side.and client side;
when sending file first send information server file , wait response server.
try { system.windows.forms.openfiledialog ofd = new system.windows.forms.openfiledialog(); ofd.multiselect = false; ofd.filename=""; if(ofd.showdialog() == system.windows.forms.dialogresult.ok) { filesendpath = ofd.filename; senderfilestream = system.io.file.open(filesendpath,system.io.filemode.open); sendertotalbytes = senderfilestream.length; filesendcommand = "@file@" + system.io.path.getfilename(filesendpath) + ";" + senderfilestream.length; senderfilestream.position = 0; sendertc.beginconnect(ip.address,55502,fileconnect,null); } else { //no file selected } } catch(exception ex) { //error connecting log error }
if connection successfull , send file command , wait response ;
public void fileconnect(iasyncresult ar) { if(ar.iscompleted) { sender.endconnect(ar); if(sender.connected) { sender.getstream().write(tobyte(filesendcommand,256),0,256); sender.getstream().beginread(computernamebuffer,0,256,filesendcylestarter,null); } } }
when response received if successfull accepted;
public void filesendcylestarter(iasyncresult ar) { if(ar.iscompleted) { if(sender.connected) { string kabul = tostring(computernamebuffer); if(kabul == "@fileaccepted@") { senderfilestream.beginread(filesendbuffer,0,1024,filesendcyle,null); } } } }
sending file has 3 steps;
1-read chunk start
2-then send chunk server.if completed send @fileend@ command , skip step 3 3-read next chunk of file
4-return step 2 if file isnt completed
step 1 :
senderfilestream.beginread(filesendbuffer,0,1024,filesendcyle,null);
step 2-4 :
public void filesendcyle(iasyncresult ar) { if(ar.iscompleted) { if(sendertc.connected) { int read = senderfilestream.endread(ar); if(read > 0) { sendertc.getstream().beginwrite(filesendbuffer,0,read,filesendcyle2,null); } else { sendertc.getstream().write(tobyte("@fileend@",256),0,256); } } } }
step 3 :
public void filesendcyle2(iasyncresult ar) { if(ar.iscompleted) { if(sendertc.connected) { sendertc.getstream().endwrite(ar); senderfilestream.beginread(filesendbuffer,0,1024,filesendcyle,null); } } }
in abowe example there 2 methods called tostring() , tobyte().i used them converting strings bytes , bytes strings.here them ;
public string tostring(byte[] buffer) { return encoding.utf8.getstring(buffer).replace("\0",""); } public byte[] tobyte(string str,int bufferlenght) { byte[] buffer = new byte[256]; encoding.utf8.getbytes(str,0,str.length,buffer,0); return buffer; }
the code abowe example isn't perfect , need lots of error handling , flow controls.i write theese give idea , jump start.
hope part of helps ^_^
Comments
Post a Comment