File server and client
GENERAL USAGE
—————————————
Start server.java first by typing “java server” in a terminal window.
Start the client.java by typing “java client ‘host-name’ ‘file-name’” in a terminal
window where host-name is the host to use and file-name is the required file.這個是單線程處理,接受連接請求和處理連接是基本的業務邏輯。
Server:
//*****************************************************************
// server.java
//
// Allows clients to connect and request files. If the file
// exists it sends the file to the client.
//*****************************************************************
import java.lang.*;
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class server
{
private final static int PORT = 12345;
private final static int QUEUE_SIZE = 10;
private final static int BUF_SIZE = 4096;
public static void main(String[] args)
{
try {
// Create the server socket
ServerSocket sSocket = new ServerSocket(PORT, QUEUE_SIZE);
// Socket is set up and will wait for connections
while (true) { //不用true會好一些
// Listen for a connection to be made to this socket and accept it
Socket cSocket = sSocket.accept();
byte[] byteArray = new byte[BUF_SIZE];
// Get the name of the file from the client
Scanner scn = new Scanner(cSocket.getInputStream());
String fileName = scn.next();
// Send the contents of the file
BufferedInputStream bis = new
BufferedInputStream(new FileInputStream(fileName));
OutputStream outStream = cSocket.getOutputStream();
while(bis.available() > 0) {
bis.read(byteArray, 0, byteArray.length);
outStream.write(byteArray, 0, byteArray.length);
}
// Close
bis.close();
cSocket.close();
}
}
catch(EOFException eofe) {
eofe.printStackTrace();
System.exit(1);
}
catch(FileNotFoundException fnfe) {
fnfe.printStackTrace();
System.exit(1);
}
catch(IllegalArgumentException iae) {
iae.printStackTrace();
System.out.println("Bind failed");
System.exit(1);
}
catch(IOException ioe) {
ioe.printStackTrace();
System.out.println("Could not complete request");
System.exit(1);
}
}
}
Client:
//*****************************************************************
// client.java
//
// Connects to the server and sends a request for a file by
// the file name. Prints the file contents to standard output.
//*****************************************************************
import java.lang.*;
import java.io.*;
import java.net.*;
public class client
{
private final static int PORT = 12345;
private final static int BUF_SIZE = 4096;
public static void main(String[] args)
{
// Set up socket using host name and port number
try {
// Get host name and file name from command line arguments
String host = args[0];
String fileName = args[1];
Socket s = new Socket(host, PORT);
byte[] byteArray = new byte[BUF_SIZE];
// Send filename to the server
PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
pw.println (fileName);
// Get the file from the server and print to command line
DataInputStream fromServer = new DataInputStream(s.getInputStream());
while(fromServer.read(byteArray) > 0) {
System.out.println(new String(byteArray, "UTF-8"));
}
fromServer.close();
s.close();
}
catch(IndexOutOfBoundsException iobe) {
System.out.println("Usage: client host-name file-name");
System.exit(1);
}
catch(UnknownHostException unhe) {
unhe.printStackTrace();
System.out.println("Unknown Host, Socket");
System.exit(1);
}
catch(IOException ioe) {
ioe.printStackTrace();
System.exit(1);
}
}
}
注意:
Server進入Socket cSocket = sSocket.accept();
的時候,判斷語句內容其實不是很重要,有的地方寫成 if ( !serverSocket.close( )){
假設我們一定要進入accept(),那含義是一樣的。ServerSocket的accept()本身是個當前線程阻塞方法(一個線程在執行過程中暫停,以等待某個條件的觸發,或者說是等待所有資源到位),那么,當它只有接受一個客戶端的鏈接時,才會往下執行,在此之前將一直等待,無限原地循環,如果直接關閉ServerSocket,那么會報socket異常,因為:
public Socket accept() throws IOException {
if (isClosed())
throw new SocketException("Socket is closed"); //here
if (!isBound())
throw new SocketException("Socket is not bound yet");
Socket s = new Socket((SocketImpl) null);
implAccept(s);
return s;
}
解決方案,可以創建一個新的socket鏈接,并且改變flag值:
public void stopThread(){
this.flag = false;
try {
new Socket("localhost",50001);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
網上看到的另外一個版本:
Server:
package socket;
import java.io.*;
import java.net.*;
public class TcpServer {
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(9091);
try {
Socket client = server.accept();
try {
BufferedReader input =
new BufferedReader(new InputStreamReader(client.getInputStream()));
boolean flag = true;
int count = 1;
while (flag) {
System.out.println(客戶端要開始說話了,這是第 + count + 次!);
count++;
String line = input.readLine();
System.out.println(客戶端說: + line);
if (line.equals(exit)) {
flag = false;
System.out.println(客戶端不想玩了!);
} else {
System.out.println(客戶端說: + line);
}
}
} finally {
client.close();
}
} finally {
server.close();
}
}
}
Client:
package socket;
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class TcpClient {
public static void main(String[] args) throws Exception {
Socket client = new Socket(127.0.0.1, 9091);
try {
PrintWriter output =
new PrintWriter(client.getOutputStream(), true);
Scanner cin = new Scanner(System.in);
String words;
while (cin.hasNext()) {
words = cin.nextLine();
output.println(words);
System.out.println(寫出了數據: + words);
}
cin.close();
} finally {
client.close();
}
}
}
這是一個socket套接字通信的圖: