Witam, mam taki problem. Napisałem program, który powinien być zdalnie sterowany. Wszystko działa ładnie, ale kiedy próbuję wysłać plik, to przesyła z prędkością nie większą niż 1Mb/s nawet jeżeli serwer i klient znajdują się na tym samym komputerze. Jak zmienić program, aby działał prawidłowo i szybko?
Poniżej załączam najważniejsze klasy:
Serwer:
public class TransferingFileObject
{
private static System.Collections.Generic.List<TransferingFileObject> transfers = new List<TransferingFileObject>();
private string sessid;
private string name;
private long size;
private long transfered =0;
private DateTime lastChange = DateTime.Now;
private System.IO.FileInfo file;
private System.IO.FileStream stream;
private TransferingFileObject(String session, String name, long size)
{
this.sessid = session;
this.name = name;
this.size = size;
this.file = new FileInfo("music_files/"+name);
Console.WriteLine("Odbieranie: "+name+" o rozmiarze: "+size+" od"+session);
if(!this.file.Exists){
stream = file.OpenWrite();
}else{
throw new Exception("File in use");
}
}
private void NewDate(){
this.lastChange = DateTime.Now;
}
public int KeepTransfering(byte[] buffer, int size){
stream.Write(buffer, 0, size);
this.transfered +=size;
NewDate();
return 0;
}
public long EndTransfering(){
stream.Close();
if(this.transfered==this.size){
Console.WriteLine("Wyslano");
return this.transfered;
}else{
Console.WriteLine("Blad wysylania pliku");
this.file.Delete();
return -this.transfered;
}
}
public static TransferingFileObject Find(String sessid, String name){
foreach(TransferingFileObject obj in transfers){
if((obj.sessid==sessid)&&(obj.name==name)){
return obj;
}
}
return null;
}
public static TransferingFileObject Create(String session, String name, long size){
foreach(TransferingFileObject item in transfers){
if(item.name==name){
return null;
}
}
TransferingFileObject obj = new TransferingFileObject(session, name, size);
transfers.Add(obj);
return obj;
}
}
Klient:
public class TransferingFileObject
{
private static int BUFFER_SIZE = 4096;
string name;
Stream stream;
long length;
private long transfered = 0;
LanConnector connector;
IConnection conn;
string sessid;
bool active = true;
public TransferingFileObject(LanConnector connector,IConnection conn, Stream fileStream, String name){
this.stream = fileStream;
this.name = name;
this.length = fileStream.Length;
this.connector = connector;
this.conn =conn;
this.sessid = connector.GetSessionID();
}
public bool Transfer(){
int id = conn.StartTransferingFile(sessid, name, length);
if(id<0){
Console.WriteLine("Blad:"+id);
return false;
}
StartTransfering st = new StartTransfering(KeepTransfering);
st.BeginInvoke(null, null);
TransferingFileForm tff = new TransferingFileForm(this);
tff.ShowDialog();
return true;
}
private delegate void StartTransfering();
private void KeepTransfering(){
Console.WriteLine("Trwa wysylanie");
byte [] buffer = new byte[BUFFER_SIZE];
int readCount;
while(active&&((readCount=stream.Read(buffer,0,BUFFER_SIZE))!= 0)){
conn.KeepTransferingFile(sessid, name, buffer, readCount);
transfered += readCount;
}
conn.EndTransferingFile(sessid, name);
Console.WriteLine("Koniec wysylania");
transfered = -1;
}
public long Size(){
return length;
}
public long State(){
return transfered;
}
public string Name(){
return name;
}
public void Abort(){
active = false;
}
}
Obiekty klasy Connector odpowiada za połaczenie, a po interfejsie IConnection dziedziczy klasa oznaczona jako MarshalByRef zawierajaca funkcje:
public class Connection: MarshalByRefObject, IConnection{
public int StartTransferingFile(String session, String name, long size){
try{
TransferingFileObject.Create(session, name, size);
}catch(Exception){
return -1;
}
return 0;
}
public int KeepTransferingFile(String session, String name, byte [] bytes, int size){
TransferingFileObject.Find(session, name).KeepTransfering(bytes, size);
return 0;
}
public int EndTransferingFile(String session, String name){
if(TransferingFileObject.Find(session, name).EndTransfering()>0){
//MainClass.singelton.playlist.LoadUtwor(name);
//MainClass.singelton.playlist.SaveXml();
}
return 0;
}
}
Jest ona tworzona na serwerze i udostępniana klientowi metodą remoting:
public LanConnector(){
int port = 3030;
c = new HttpChannel(port);
ChannelServices.RegisterChannel(c);
LogConsole.WriteLine("Nasłuchiwanie portu "+port);
Type t = typeof(Connection);
RemotingConfiguration.RegisterWellKnownServiceType(t, "conn", WellKnownObjectMode.Singleton);
conn = (Connection)Activator.GetObject(t, "http://localhost:3030/conn");
}
U klienta:
Type t = typeof(IConnection);
conn = (IConnection)Activator.GetObject(t, "http://"+address+"/conn");
Wspomnę jeszcze, że zdalnie spisuje sie prawidłowo wykorzystując dobrze łacze, ale dla połaczenia localhost przesłanie do programu 50Mb plików mp3 trwa prawie godzinę.
Możecie sami się przekonać pobierając ten program: http://lanplayer.sourceforge.net/
Cały kod dostępny jest na http://lanplayer.svn.sourceforge.net/viewvc/lanplayer/ jesli moje fragmenty nie wystarczą do rozwiązania problemu.