gvsu/cs654/proj1/KaZaClient.java
josh 32633264d5 commented classes and functions
git-svn-id: svn://anubis/gvsu@65 45c1a28c-8058-47b2-ae61-ca45b979098e
2008-03-09 23:41:34 +00:00

277 lines
9.1 KiB
Java

/* Author: Josh Holtrop
* GVSU, CS654, Project 1
* Date: 2008-03-11
*/
import java.io.*;
import java.net.*;
import java.util.*;
/* KaZaClient implements a file server client which can connect
* to a "Mini Napster Hub" (implemented in KaZaServer) and search
* for files to download. The files shared by the KaZaClient are
* stored in a directory and described by ".kaza" files. The format
* of a .kaza description file is a plain text file containing two
* lines, the first of which is the name of the actual file to
* share and the second of which is a brief description of the file.
*/
public class KaZaClient
{
public static final int LISTEN_PORT = 3443;
private static int m_transferIndex = 0;
private String m_sharedFolder;
private boolean m_connected = false;
private Socket m_socket;
private DataOutputStream m_os;
private FileServer m_fileServer;
private HashMap<Integer, ClientDownloader> m_clientDownloaders;
/* make a KaZaClient object using the given user name,
* connection speed (Kbps), path to the directory of shared files,
* and hostname of the MNH group leader to connect to */
public KaZaClient(String userName, int kbps,
String sharedFolder, String server)
{
m_sharedFolder = sharedFolder;
if (userName == null || userName.trim().equals(""))
userName = "Anonymous";
try {
m_socket = new Socket(server, KaZaServer.LISTEN_PORT);
m_os = new DataOutputStream(m_socket.getOutputStream());
m_os.writeBytes("HELO " + userName + "\n");
m_os.writeBytes("SPED " + kbps + "\n");
File sharedDir = new File(m_sharedFolder);
if (sharedDir.isDirectory())
{
String[] files = sharedDir.list();
for (String fName : files)
{
if (fName.endsWith(".kaza"))
{
/* we found a description file, publish this file */
FileInputStream fis = new FileInputStream(m_sharedFolder +
File.separator +
fName);
BufferedReader br = new BufferedReader(
new InputStreamReader(fis));
String sharedFileName = br.readLine();
String sharedFileDesc = br.readLine();
m_os.writeBytes("DESC " + sharedFileName + "\n" +
sharedFileDesc + "\n");
}
}
}
} catch (Exception e) {
return;
}
m_fileServer = new FileServer(LISTEN_PORT, m_sharedFolder);
Thread fsThread = new Thread(m_fileServer);
fsThread.start();
m_connected = true;
m_clientDownloaders = new HashMap<Integer, ClientDownloader>();
}
/* check if a given file download is still active */
public boolean isDownloadActive(int index)
{
synchronized (m_clientDownloaders)
{
return m_clientDownloaders.containsKey(index);
}
}
/* check if the client is connected */
public boolean connected() { return m_connected; }
/* close the client, sends QUIT message to MNH server */
public void close()
{
if (m_connected)
{
try {
m_os.writeBytes("QUIT\n");
m_os.close();
m_socket.close();
} catch (Exception e) { }
m_connected = false;
}
}
/* this method is called when the user wants the client
* to send a search message to its MNH group leader */
public Vector<SearchResult> performSearch(String query)
{
Vector<SearchResult> results = new Vector<SearchResult>();
try
{
m_os.writeBytes("SRCH 2 " + query + "\n");
BufferedReader br = new BufferedReader(
new InputStreamReader(
m_socket.getInputStream()));
for (;;)
{
String resultStr = br.readLine();
if (resultStr.equals("."))
break;
StringTokenizer tokens = new StringTokenizer(resultStr, "|");
SearchResult result = new SearchResult();
for (int i = 0; i < 5; i++)
{
if (tokens.hasMoreTokens())
{
String t = tokens.nextToken();
switch (i)
{
case 0:
result.peerAddress = t;
break;
case 1:
result.userName = t;
break;
case 2:
result.speed = Integer.parseInt(t);
break;
case 3:
result.fileName = t;
break;
case 4:
result.fileDescription = t;
break;
}
}
}
results.add(result);
}
}
catch (Exception e) { }
/* sort the results by the connection speed */
Object[] arr = results.toArray();
java.util.Arrays.sort(arr, new Comparator() {
public int compare(Object o1, Object o2) {
return ((SearchResult)o1).speed - ((SearchResult)o2).speed;
}
});
results = new Vector<SearchResult>();
for (Object o : arr)
{
results.add((SearchResult) o);
}
return results;
}
/* SearchResult stores data fields describing a "hit" that is returned
* by the MNH group leader */
public class SearchResult
{
String peerAddress = "";
String userName = "";
int speed = 0;
String fileName = "";
String fileDescription = "";
public String toString()
{
return "User: \"" + userName + "\" [" +
peerAddress + ", " + getSpeedString(speed) +
"], File: \"" +
fileName + "\" (" + fileDescription + ")";
}
/* val is measured in Kbps */
private String getSpeedString(int val)
{
if (val > 999999)
return (val/1000000) + " Gbps";
if (val > 999)
return (val / 1000) + " Mbps";
return val + " Kbps";
}
}
/* called by the user instructing the KaZaClient to begin
* downloading a file from a peer user */
public int downloadFile(String host, String fileName)
{
ClientDownloader cd = new ClientDownloader(host, fileName);
synchronized (m_clientDownloaders)
{
m_clientDownloaders.put(cd.getIndex(), cd);
}
Thread t = new Thread(cd);
t.start();
return cd.getIndex();
}
/* this method returns a unique index for a given file download */
public synchronized int getTransferIndex()
{
return m_transferIndex++;
}
/* this class implements a threaded file downloader so that a
* file download can occur at the same time that the user is
* searching for other files or downloading other files */
public class ClientDownloader implements Runnable
{
private String m_host;
private String m_fileName;
private int m_index;
public ClientDownloader(String host, String fileName)
{
m_host = host;
m_fileName = fileName;
m_index = getTransferIndex();
}
public int getIndex() { return m_index; }
public void run()
{
FileOutputStream fos;
try {
fos = new FileOutputStream(m_fileName);
} catch (Exception e) {
return;
}
try
{
Socket socket = new Socket(m_host, LISTEN_PORT);
DataOutputStream os = new DataOutputStream(socket.getOutputStream());
DataInputStream is = new DataInputStream(socket.getInputStream());
os.writeBytes(m_fileName + "\n");
byte[] buff = new byte[1500];
for (;;)
{
int bytesRead = is.read(buff, 0, buff.length);
if (bytesRead < 0)
break;
fos.write(buff, 0, bytesRead);
}
}
catch (Exception e) { }
try {
fos.close();
} catch (Exception e) {
}
synchronized (m_clientDownloaders)
{
m_clientDownloaders.remove(getIndex());
}
}
}
}