基於TCP/UDP的網路聊天程式
阿新 • • 發佈:2019-02-18
最近網路結課剛好梳理一下所學的知識。
想要做一個網路聊天的程式,就要先知道需要用到什麼知識和工具。
分享下別人寫的Socket程式設計知識連結
Socket程式設計
基於TCP實現網路聊天1.0(無圖形化介面):
伺服器端Service:
基於UDP實現網路聊天(無圖形化介面):
處理類Handler:/*伺服器端*/ 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(); } } }
客戶端Client: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(); } } } }
ps:在執行過程中發現了伺服器端沒有響應的問題。 readLine()方法在進行讀取一行時,只有遇到回車(\r)或者換行符(\n)才會返回讀取結果,這就是“讀取一行的意思”,重要的是readLine()返回的讀取內容中並不包含換行符或者回車符;並且,當realLine()讀取到的內容為空時,並不會返回 null,而是會一直阻塞,只有當讀取的輸入流發生錯誤或者被關閉時,readLine()方法才會返回null。/*客戶端*/ 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(); } } }
由於在客戶端使用的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();
}
}
}