1. 程式人生 > >基於TCP/UDP的網路聊天程式

基於TCP/UDP的網路聊天程式

最近網路結課剛好梳理一下所學的知識。 想要做一個網路聊天的程式,就要先知道需要用到什麼知識和工具。 分享下別人寫的Socket程式設計知識連結  Socket程式設計 基於TCP實現網路聊天1.0(無圖形化介面): 伺服器端Service:
/*伺服器端*/
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
public class Service {
	public static void main(String args[]) 
	{
		ServerSocket serverSocket;     //建立ServerSocket服務物件
		System.out.println("------Server------");
		try {
			serverSocket=new ServerSocket(2046);   //在2046埠建立監聽
			System.out.println("伺服器監聽建立,等待連線...");
			Socket socket=serverSocket.accept(); //產生阻塞直至客戶端連線
			System.out.println("已成功連線!");
			Thread thread=new Thread(new Handler(socket));    //建立新執行緒
			thread.start();     //啟動執行緒
			serverSocket.close();   //關閉服務
		}
		catch(SocketException e)
		{
			e.printStackTrace();
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
}
處理類Handler:
import java.net.Socket;
import java.util.Scanner;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.io.IOException;

public class Handler implements Runnable {
	private Socket socket;
	Handler(Socket socket)
	{
		this.socket=socket;
	}
	public void run()
	{
		try {
			System.out.println("新連線:"+socket.getInetAddress()+":"+socket.getPort());
			InputStreamReader isr=new InputStreamReader(socket.getInputStream());
			BufferedReader br=new BufferedReader(isr);
			String words;
			while((words=br.readLine())!=null)
			{
				System.out.println("收到訊息:"+words);
				Writer writer=new OutputStreamWriter(socket.getOutputStream());
				System.out.println("請輸入回覆:");
				Scanner sc=new Scanner(System.in);
				String content=sc.nextLine();
				writer.write(content+"\n");
				Thread.sleep(10000);
				writer.flush();
				sc.close();
			}		
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		finally 
		{
			try {
				System.out.println("關閉連線:"+socket.getInetAddress()+":"+socket.getPort());
				if(socket!=null)
				{
				socket.close();
				}
			}catch(IOException e)
			{
				e.printStackTrace();
			}
		}
	}
}
客戶端Client:
/*客戶端*/
import java.net.Socket;
import java.io.OutputStreamWriter;
import java.io.InputStreamReader;
import java.io.Writer;
import java.io.BufferedReader;
import java.util.Scanner;
public class Client {
	public static String serverId="此處輸入IP地址";
	public static void main(String args[])
	{
		System.out.println("------Client------");
		Socket socket;
		Scanner sc;
		try {
			socket=new Socket(serverId,2046); //建立連線
			System.out.println("連線已建立!");
			Writer writer=new OutputStreamWriter(socket.getOutputStream());
			System.out.println("請輸入訊息:");
			sc=new Scanner(System.in);
			String content=sc.nextLine();
			writer.write(content+"\n");
			writer.flush();
			System.out.println("訊息已發出!");
			InputStreamReader isr=new InputStreamReader(socket.getInputStream());
			BufferedReader br=new BufferedReader(isr);
			System.out.println("收到訊息:"+br.readLine());
			socket.close();
			}
		catch(Exception e) 
		{
			e.printStackTrace();
		}
	}
}
ps:在執行過程中發現了伺服器端沒有響應的問題。 readLine()方法在進行讀取一行時,只有遇到回車(\r)或者換行符(\n)才會返回讀取結果,這就是“讀取一行的意思”,重要的是readLine()返回的讀取內容中並不包含換行符或者回車符;並且,當realLine()讀取到的內容為空時,並不會返回 null,而是會一直阻塞,只有當讀取的輸入流發生錯誤或者被關閉時,readLine()方法才會返回null。

由於在客戶端使用的readLine()來讀取使用者輸入,所以當用戶按下回車鍵是,readLine() 返回讀取內容,但此時返回的內容並不包含換行符,而當在伺服器端用readLine()再次讀取時,由於讀取的內容沒有換行符,所以readLine()方法會一直阻塞等待換行符,這就是伺服器端沒有輸出的原因。

解決方法:在客戶端每次輸入回車後,手動給輸入內容加入"\n"或"\r",再寫入伺服器。

基於TCP實現網路聊天2.0(圖形化介面):
/*客戶端*/
import java.net.Socket;
import java.io.OutputStreamWriter;
import java.io.InputStreamReader;
import java.io.Writer;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class Client extends JFrame {
	public static String serverId="輸入IP地址";
	private static JTextField jip;        //IP地址
	private static JButton connect;       //連線按鈕
	private static JTextArea ta;          //聊天區域
	private static JTextField text;       //輸入訊息
	private static JButton send;          //傳送按鈕
	private static JButton stop;          //停止服務按鈕
	Socket socket;
	Client()
	{
		JFrame frame=new JFrame("網路聊天---客戶端");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(600, 420);
		Container c=frame.getContentPane();
		c.setLayout(new FlowLayout()); 
		JTextField address=new JTextField("請輸入要連線的IP:",20);
		jip=new JTextField("10.101.219.78",20);
		connect=new JButton("連線");
		connect.addActionListener(new ActionListener() //新增連線按鈕監聽事件
		{
			public void actionPerformed(ActionEvent e)
			{
				try
				{
					socket=new Socket(serverId,2046); //建立連線
					ta.append("連線已建立!");
				}
				catch(Exception ex)
				{
					ex.printStackTrace();
				}
			}
		});        
		ta=new JTextArea(15,52);    
		text=new JTextField(40);           
		send=new JButton("傳送");     
		send.addActionListener(new ActionListener()   //添加發送按鈕監聽事件
		{
			public void actionPerformed(ActionEvent e)
			{
				try {
					Writer writer=new OutputStreamWriter(socket.getOutputStream());
					ta.append("請輸入訊息:"+"\n");
					String s=text.getText();
					ta.append("我:"+s+"\n");
					writer.write(s+"\n");
					writer.flush();
					ta.append("訊息已發出!"+"\n");
					InputStreamReader isr=new InputStreamReader(socket.getInputStream());
					BufferedReader br=new BufferedReader(isr);
					ta.append("收到訊息:"+br.readLine());
				}
				catch(Exception ex)
				{
					ex.printStackTrace();
				}
			}
		});        
		stop=new JButton("停止服務");
		stop.addActionListener(new ActionListener()    //新增停止服務按鈕監聽事件
		{
			public void actionPerformed(ActionEvent e)
			{
				try {
					socket.close();
					}
				catch(Exception ex) 
				{
					ex.printStackTrace();
				}		
			}
		});        
		c.add(address);
		c.add(jip);
		c.add(connect);
		c.add(ta);
		c.add(text);
		c.add(send);
		c.add(stop);
		frame.setVisible(true);
	}
	public static void main(String args[])
	{
		Client client=new Client();
		ta.append("請建立連線!");
	}
}
伺服器:
/*伺服器端*/
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class Service extends JFrame{
	private static Service service=new Service();
	private static ServerSocket serverSocket;     //建立ServerSocket服務物件
	private static Socket socket;
	public static JTextArea ta;     //聊天區域
	public static JTextField text;  //訊息輸入
	public static JButton send;     //傳送按鈕
	Service()
	{
		JFrame frame=new JFrame("網路聊天---伺服器");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(600, 400);
		Container c=frame.getContentPane();
		c.setLayout(new FlowLayout()); 
		ta=new JTextArea(15,52);     
		text=new JTextField(40);     
		send=new JButton("傳送"); 
		send.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				try {
					Writer writer=new OutputStreamWriter(socket.getOutputStream());
					ta.append("請輸入訊息:"+"\n");
					String s=text.getText();
					ta.append("我:"+s+"\n");
					writer.write(s+"\n");
					writer.flush();
					ta.append("訊息已發出!"+"\n");
				}
				catch(Exception ex)
				{
					ex.printStackTrace();
				}
			}
		});
		c.add(ta);
		c.add(text);
		c.add(send);
		frame.setVisible(true);
	}
	public static void main(String args[]) 
	{
		try {
			serverSocket=new ServerSocket(2048);   //在2046埠建立監聽
			ta.append("伺服器監聽建立,等待連線..."+"\n");
			socket=serverSocket.accept(); //產生阻塞直至客戶端連線
			ta.append("已成功連線!"+"\n");
			Thread thread=new Thread(new Handler(socket));    //建立新執行緒
			thread.start();     //啟動執行緒
			serverSocket.close();   //關閉服務
		}
		catch(SocketException e)
		{
			e.printStackTrace();
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
}
處理器類:
import java.net.Socket;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Handler implements Runnable {
	private Socket socket;
	Handler(Socket socket)
	{
		this.socket=socket;
	}
	public void run()
	{
		try {
			System.out.println("新連線:"+socket.getInetAddress()+":"+socket.getPort());
			InputStreamReader isr=new InputStreamReader(socket.getInputStream());
			BufferedReader br=new BufferedReader(isr);
			String words;
			while((words=br.readLine())!=null)
			{
				Service.ta.append("收到訊息:"+words+"\n");
				Service.ta.append("請輸入回覆:"+"\n");
			}		
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		finally 
		{
			try {
				System.out.println("關閉連線:"+socket.getInetAddress()+":"+socket.getPort());
				if(socket!=null)
				{
				socket.close();
				}
			}catch(IOException e)
			{
				e.printStackTrace();
			}
		}
	}
}
最後效果展示:
基於UDP實現網路聊天(無圖形化介面):
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
/*傳送方*/
public class Send {
	public static void main(String args[])throws IOException
	{
		DatagramSocket ds1=new DatagramSocket();     //傳送埠
		DatagramSocket ds2=new DatagramSocket(4000);  //接收埠
		int port=3000;     //埠號
		InetAddress IP=InetAddress.getByName("10.101.219.78");
		while(true)
		{
			Scanner sc=new Scanner(System.in);
			System.out.println("請輸入傳送內容:");
			String content=sc.nextLine();
			byte[] buffer=content.getBytes();
			int length=buffer.length;
			DatagramPacket dp1=new DatagramPacket(buffer,length,IP,port);
			ds1.send(dp1);
			byte[] buffer1=new byte[1024];   //接收
			int len=buffer1.length;
			DatagramPacket dp2=new DatagramPacket(buffer1,len);
			ds2.receive(dp2);
			byte[] words=dp2.getData();
			int leng=words.length;
			InetAddress address=dp2.getAddress();
			String ip=address.getHostAddress();
			System.out.println(ip+"說"+new String(words,0,leng));
		}	
			//sc.close();
			//ds1.close();
			//ds2.close();
	}
}
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
/*接收方*/
public class Receive {
	public static void main(String args[])throws IOException
	{
		int port=4000;    //接收方給傳送方的埠
		InetAddress IP=InetAddress.getByName("10.101.219.78");
		DatagramSocket ds1=new DatagramSocket(3000);     //接收埠
		DatagramSocket ds2=new DatagramSocket();   //傳送埠埠
		
		while(true)
		{
			byte[] buffer1=new byte[1024];
		    int length=buffer1.length;
			DatagramPacket dp=new DatagramPacket(buffer1,length);
			ds1.receive(dp);
			byte[] words=dp.getData();
			int len=words.length;
			InetAddress address=dp.getAddress();
			String ip=address.getHostAddress();
			System.out.println(ip+"說"+new String(words,0,len));
			System.out.println("請輸入回覆訊息:");
			Scanner sc=new Scanner(System.in);
			String content=sc.nextLine();
			byte[] buffer2=content.getBytes();
			int leng=buffer2.length;
			DatagramPacket dp1=new DatagramPacket(buffer2,leng,IP,port);
			ds2.send(dp1);
			System.out.println("傳送成功!");
			//sc.close();
			//ds1.close();
			//ds2.close();
		}
	}
}