TCP、UDP練習題 (UDP聊天程序、TCP上傳文本文件和圖片文件)

TCP、UDP編程練習


TCP

☆上傳文本文件

讀取一個本地文本文件,將數據發送到服務端,服務器端對數據進行存儲。 存儲完畢後,給客戶端一個提示。

一、解題思路

客戶端:(1) 創建Socket對象----用服務器的ip+端口號

(2)讀取文件內容

(3)通過socket把內容發送給服務器端(把socket中的輸出流包裝成“打印流”來進行發送文本,是一種比較安全的輸出方式,不會出現失真。)


服務器端:(1) 創建服務器socket---ServerSocket

    (2)通過ServerSocket獲得客戶端的socket

    (3)通過客戶端的socket,讀取對方發來的數據,並把這些數據寫到一個新建文件當中


二、註解和實現代碼

UploadTextClient.java類

package net.tcp.textFileUpload;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

public class UploadTextClient {

	public static void main(String[] args) {
		try {
			//1 創建Socket對象----用服務器的ip+端口號
			Socket s = new Socket("127.0.0.1", 10000);

			//2 讀取文件內容   //3 通過socket把內容發送給服務器端(把socket中的輸出流包裝成“打印流”來進行發送文本,是一種比較安全的輸出方式,不會出現失真。)
			BufferedReader bufr = new BufferedReader( new FileReader("tempFile\\client.txt") );
			PrintWriter out = new PrintWriter(s.getOutputStream(), true);
			//發送
			String line = null;
			while((line=bufr.readLine())!=null){
				out.println(line);
			}

			//6 給服務器發送一個結束標記
			//out.println("%$#@88##K##");//發送自定義的結束標記
			s.shutdownOutput();
			
			//5 讀取服務器端的反饋信息 s.getInputStream()
			BufferedReader bufr2 = new BufferedReader( new InputStreamReader(s.getInputStream()) );
			String text = bufr2.readLine();
			System.out.println("server:"+text);
			
			//4 關流
			bufr.close();
			out.close();
			s.close();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}

}

UploadTextServer.java類

package net.tcp.textFileUpload;

import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class UploadTextServer {

	public static void main(String[] args) {
		try {
			//1 創建服務器socket---ServerSocket
			ServerSocket server = new ServerSocket(10000);
			//2 通過ServerSocket獲得客戶端的socket
			Socket s = server.accept();
			//3 通過客戶端的socket,讀取對方發來的數據,並把這些數據寫到一個新建文件當中
			//源:socket-->s.getInputStream()-->BufferedReader    目的:FileWriter("tempFile\\server.txt")--> 可以包裝成PrintWriter來進行輸出
			BufferedReader bufr = new BufferedReader(new InputStreamReader(s.getInputStream()));
			PrintWriter pw = new PrintWriter( new FileWriter("tempFile\\server.txt") ,true);
			String line = null;
			while((line=bufr.readLine())!=null){
//				if("%$#@88##K##".equals(line)){
//					break;
//				}
				pw.println(line);
			}
			
			//5 向客戶端發送反饋信息,通過客戶端的socket來發
			String str = s.getInetAddress().getHostName();
			str = str + "::: 文件上傳成功...";
			PrintWriter out = new PrintWriter(s.getOutputStream(),true);
			out.println(str);
			
			//4 關流
			bufr.close();
			pw.close();
			s.close();
			server.close();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		
	}

}



☆上傳圖片文件

客戶端需求:把一個圖片文件發送到服務端並讀取回饋信息。要求判斷文件是否存在及格式是否爲jpg或gif並要求文件小於2M。

服務端需求:接收客戶端發送過來的圖片數據。進行存儲後,回饋一個 上傳成功字樣。支持多用戶的併發訪問。

一、解題思路

客戶端:(1)判斷文件輸出的文件是否存在:file.exists() && file.isFile()

      (2)判斷文件的格式問題:file.getName().endsWith(".jpg")||file.getName().endsWith(".gif")

      (3)文件小於2M:file.length()>=1024*1024*2

      (4)然後通過IO讀出文件的數據,並通過Socket將其發送給服務器端

注:在文件發送完後,記得給一個發送結束標誌 s.shutdownOutput(),這句相當重要哦!!!


服務器端:主要就是解決多個客戶端同時向服務器傳送圖片時,服務器端如何處理的問題。方法是通過new一個線程來解決。只要有客戶端請求,就new一個線

程單獨的與其交流,這要做的好處,滿足了每個客戶端同時和一個服務器進行多次交流。

二、註解和實現代碼

UploadPicClient.java類

package net.tcp.picFileUpload;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class UploadPicClient {

	public static void main(String[] args) throws Exception{
		//衛條件,反邏輯
		if(args.length!=1){
			System.out.println("請指定文件名");
			return;
		}
		File file = new File(args[0]);
		if( !(file.exists() && file.isFile()) ){
			System.out.println("上傳的文件不存在");
			return;
		}
		if( !(file.getName().endsWith(".jpg")||file.getName().endsWith(".gif")) ){
			System.out.println("文件的擴展名必須是jpg或gif!");
			return;
		}
		if( file.length()>=1024*1024*2 ){
			System.out.println("文件過大,必須小於2M,請重新選擇...");
			return;
		}
		
		
		Socket s = new Socket("127.0.0.1",10002);
		FileInputStream fis = new FileInputStream(file);
		OutputStream out = s.getOutputStream();
		byte buf[] = new byte[1024];
		int len=0;
		while((len=fis.read(buf))!=-1){
			out.write(buf, 0, len);
		}
		
		s.shutdownOutput();//發送結束標記
		
		//讀取服務器的反饋信息
		InputStream in = s.getInputStream();
		byte b[] = new byte[1024];
		int len2 = in.read(b);
		String info = new String(b,0,len2);
		System.out.println(info);
		
		fis.close();
		out.close();
		s.close();
	}

}
UploadPicServer.java類

package net.tcp.picFileUpload;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;


public class UploadPicServer {

	public static void main(String[] args) throws Exception{
		ServerSocket server = new ServerSocket(10002);
		while(true){
			Socket s = server.accept();
			new Thread( new UploadThread(s) ).start();
		}
	}

}

class UploadThread implements Runnable{
	private Socket s = null;
	public UploadThread(Socket s) {
		this.s = s;
	}

	@Override
	public void run() {
		
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"....connected!");
		
		//接收來自客戶端的數據(圖片文件)
		File dir= new File("c:\\mypic");
		if(!dir.exists()){
			dir.mkdir();
		}
		int count =1;
		File file = new File(dir,ip+".jpg");
		while(file.exists()){
		  file = new File(dir,ip+"("+ (count++) +").jpg");
		}
		
		
		try {
			FileOutputStream fos = new FileOutputStream(file);
			byte buf[] = new byte[1024];
			
			int len=0;
			InputStream in = s.getInputStream();
			while((len=in.read(buf))!=-1){
				fos.write(buf, 0, len);
			}
			
			OutputStream out = s.getOutputStream();
			out.write((ip+"-->圖片數據已經上傳成功!").getBytes());
			
			//關流
			out.close();
			fos.close();
			s.close();
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
}
注意一個小問題:就是在運行客戶端程序(UploadPicClient.java)時,不能直接運行。

操作步驟:鼠標放在main方法上單擊右鍵,選擇Run As ---> Run Configurations --->Arguments --->Program arguments中填寫要傳輸文件的絕對路徑,也就是路徑加文

    件名。


在客戶端與服務器進行傳輸數據時,發送端和接收端的流一定要對應。



UDP

☆UDP聊天程序

a、通過鍵盤錄入獲取要發送的信息。

b、將發送和接收分別封裝到兩個線程中。

一、解題思路

因爲是聊天程序,所以是兩個客戶端交流,所以只要寫成一個客戶端就可以,另一個只需要改一下發送端和接收端的端口。

每個客戶端都有一個發送的DatagramSocket和一個接收的DatagramSocket;然後分別通過一個線程啓動。這樣保證在沒有接到結束提示時,每個客戶端都可以一直保持接收和發送的狀態。

二、註解和實現代碼

UDPChat.java類

package net.udp.updChat;
//111111
import java.net.DatagramSocket;
import java.net.SocketException;

public class UDPChat {

	public static void main(String[] args) {
		try {
			DatagramSocket send = new DatagramSocket(10003);//發送端口
			DatagramSocket receive = new DatagramSocket(10004);//接收端口
			new Thread( new Send(send) ).start();
			new Thread( new Receive(receive) ).start();
			
		} catch (SocketException e) {
			e.printStackTrace();
		}
		
	}

}

Receive.java類

package net.udp.updChat;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class Receive implements Runnable {
	DatagramSocket ds=null;
	
	public Receive(DatagramSocket ds) {
		this.ds = ds;
	}

	@Override
	public void run() {
		try {
			
			byte buf[] = new byte[1024];
			while(true){
				DatagramPacket dp = new DatagramPacket(buf, buf.length);
				ds.receive(dp);
				String ip = dp.getAddress().getHostAddress();
				int port = dp.getPort();
				String str = new String( dp.getData(),0,dp.getLength() );
				System.out.println(ip+":"+port+"==> "+str);
				if("over".equalsIgnoreCase(str)){
					System.out.println(ip+"離開聊天室....");
				}
				
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

Send.java類

package net.udp.updChat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class Send implements Runnable {
	DatagramSocket ds=null;
	
	public Send(DatagramSocket ds) {
		this.ds = ds;
	}

	@Override
	public void run() {
		try {
			BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
			String line=null ;
			while((line= bufr.readLine())!=null){
				byte buf[] = line.getBytes();
				DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.31.115"),10002);//(10002)與另一個客戶端的接收端口相同
				ds.send(dp);
				if("over".equalsIgnoreCase(line)){
					break;
				}
			}
			ds.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}









發佈了148 篇原創文章 · 獲贊 29 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章