假設Tom和Jerry利用Java UDP進行聊天,請為他們編寫程式。
阿新 • • 發佈:2021-01-18
假設Tom和Jerry利用Java UDP進行聊天,請為他們編寫程式。具體如下:
(1)、Tom和Jerry聊天的雙方都應該具有傳送端和接收端;
(2)、利用DatagramSocket與DatagramPacket;
(3)、實現 java.lang.Runnable類,重寫 run()方法。
(4)、Tom對傳送的內容(傳送的內容為 學生本人的名字+學生本人的學號)使用對稱/非對稱加密演算法(金鑰可以自主分配,不需要權威機構來分配)來加密,然後將加密後的密文傳送給Jerry;Jerry對收到的密文進行解密,還原成明文內容(即 學生本人的名字+學生本人的學號)
RSA加密類:
package RSA;
import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
//RSA非對稱加密演算法工具類
public class RSA {
private static final String KEY_ALGORITHM = "RSA";//非對稱金鑰演算法
private static final int KEY_SIZE = 512;//金鑰長度,在512到65536位之間,建議不要太長,否則速度很慢,生成的加密資料很長
private static final String CHARSET = "UTF-8";//字元編碼格式
//生成KeyPair金鑰對
public static KeyPair getKeyPair() throws Exception {
return getKeyPair(null);
}
//生成金鑰對的密碼password
public static KeyPair getKeyPair (String password) throws Exception {
//例項化金鑰生成器
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
//初始化金鑰生成器
if(password == null){
keyPairGenerator.initialize(KEY_SIZE);
}else {
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(password.getBytes(CHARSET));
keyPairGenerator.initialize(KEY_SIZE, secureRandom);
}
//生成金鑰對
return keyPairGenerator.generateKeyPair();
}
//取得私鑰byte[]
public static byte[] getPrivateKeyBytes(KeyPair keyPair) {
return keyPair.getPrivate().getEncoded();
}
//取得Base64編碼的私鑰byte[]
public static String getPrivateKey(KeyPair keyPair) {
Return Base64.getEncoder().encodeToString(getPrivateKeyBytes(keyPair));
}
//取得公鑰byte[]
public static byte[] getPublicKeyBytes(KeyPair keyPair) {
return keyPair.getPublic().getEncoded();
}
public static String getPublicKey(KeyPair keyPair) {
return Base64.getEncoder().encodeToString(getPublicKeyBytes(keyPair));
}
//將私鑰進行加密
public static byte[] encryptByPrivateKey(byte[] data, byte[] privateKey) throws Exception {
//例項化金鑰工廠
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//生成私鑰
PrivateKey key = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey));
//資料加密
Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(data);
}
//私鑰加密
public static String encryptByPrivateKey(String data, String privateKey) throws Exception {
byte[] key = Base64.getDecoder().decode(privateKey);
return Base64.getEncoder().encodeToString(encryptByPrivateKey(data.getBytes(CHARSET), key));
}
//公鑰加密
public static byte[] encryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
//例項化金鑰工廠
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//生成公鑰
PublicKey key = keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));
//資料加密
Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(data);
}
//公鑰加密
public static String encryptByPublicKey(String data, String publicKey) throws Exception {
byte[] key = Base64.getDecoder().decode(publicKey);
return Base64.getEncoder().encodeToString(encryptByPublicKey(data.getBytes(CHARSET), key));
}
//私鑰解密
public static byte[] decryptByPrivateKey(byte[] data, byte[] privateKey) throws Exception {
//例項化金鑰工廠
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//生成私鑰
PrivateKey key = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKey));
//資料解密
Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(data);
}
//私鑰解密
public static String decryptByPrivateKey(String data, String privateKey) throws Exception {
byte[] key = Base64.getDecoder().decode(privateKey);
return new String(decryptByPrivateKey(Base64.getDecoder().decode(data), key), CHARSET);
}
//公鑰解密
public static byte[] decryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
//例項化金鑰工廠
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
//產生公鑰
PublicKey key = keyFactory.generatePublic(new X509EncodedKeySpec(publicKey));
//資料解密
Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(data);
}
//公鑰解密
public static String decryptByPublicKey(String data, String publicKey) throws Exception {
byte[] key = Base64.getDecoder().decode(publicKey);
return new String(decryptByPublicKey(Base64.getDecoder().decode(data), key), CHARSET);
}
}
xiaozou的主類:
UDPSocket_zou
package xiaozou;
public class UDPSocket_zou {
public static void main(String[] args) throws Exception {
//分別啟動傳送資訊執行緒和接收訊息執行緒
Thread thread1 = new Thread(new UDPSocketZouReceivethread());
Thread thread2 = new Thread(new
UDPSocketZouSendthread());
thread1.start();
thread2.start();
}
}
xiaozou的接收類
UDPSocketZouReceivethread
package xiaozou;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.security.KeyPair;
import RSA.RSA;
//xiaozou的接收類,生成公鑰私鑰,把公鑰通過檔案操作儲存在檔案中,用自己的私鑰解密收到的資料
public class UDPSocketZouReceivethread implements Runnable {
//接收方的套接字必須和對面傳送方指定的packet埠號相同
DatagramSocket tianSocket;
{
try {
tianSocket = new DatagramSocket(8088);
} catch (SocketException e) {
e.printStackTrace();
}
}
byte[] ibuf = new byte[1024];
//接收的資料
DatagramPacket tianPacket = new DatagramPacket(ibuf, ibuf.length);
@Override
public void run() {
//生成金鑰對
KeyPair keyPair = null;
try {
keyPair = RSA.getKeyPair();
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//公鑰
String publicKey = RSA.getPublicKey(keyPair);
//私鑰
String privateKey = RSA.getPrivateKey(keyPair);
System.out.println("公鑰:\n" + publicKey);
System.out.println("私鑰:\n" + privateKey);
File file = new File("text.txt");
BufferedWriter out = null;
//FileWriter()向檔案寫入資料
try {
out = new BufferedWriter(new FileWriter(file));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
//將公鑰寫入檔案中
out.write(publicKey);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
out.flush();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} //重新整理緩衝流
// 手動把快取區內容儲存到檔案,不然會造成資料的丟失
while (true) {
try {
tianSocket.receive(tianPacket);
} catch (IOException e) {
e.printStackTrace();
}
String s1 = new String(tianPacket.getData(), 0, tianPacket.getLength());
String s2 = null;
try {
s2 = RSA.decryptByPrivateKey(s1, privateKey);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("加密後的資料:" + s1);
System.out.println("解密後的資料:" + s2);
}
}
}
xiaozou的傳送類
UDPSocketZouSendthread
package xiaozou;
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
//實現runnable介面
public class UDPSocketZouSendthread implements Runnable {
//接收方的套接字必須和對面傳送方指定的packet埠號相同
byte[] ibuf = new byte[1024];
String message;
Scanner scanner = new Scanner(System.in);
//該類的例項物件就相當於一個集裝箱,用於封裝UDP通訊中傳送或者接收的資料。
//建立傳送型別的資料報
DatagramPacket tianPacket;
{
try {
tianPacket = new DatagramPacket(ibuf, ibuf.length, InetAddress.getByName("127.0.0.1"), 2020);//指定對面接收方的埠h號
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
//這個類的例項物件就可以傳送和接收DatagramPacket資料包
// 建立傳送方的套接字,並制定埠號和IP地址
DatagramSocket ds;
{
try {
ds = new DatagramSocket(8087, InetAddress.getByName("127.0.0.1"));//自己的埠號為8087,也可以不指定,會自動分配
} catch (SocketException | UnknownHostException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true) {
//輸入
message = scanner.nextLine();
tianPacket.setData(message.getBytes());
try {
//傳送
assert ds != null;
ds.send(tianPacket);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
xiaotian的主類:
UDPSocket_tian
package xiaotian;
public class UDPSocket_tian {
public static void main(String[] args) {
//分別啟動傳送訊息執行緒和接收訊息執行緒
Thread thread1 = new Thread(new UDPSocketTianReceivethread());
Thread thread2 = new Thread(new UDPSocketTianSendthread());
thread1.start();
thread2.start();
}
}
xiaotian的傳送類 ,用xiaozou的公鑰加密:
UDPSocketTianSendthread
package xiaotian;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
import java.security.KeyPair;
import java.util.Scanner;
import RSA.RSA;//引入加密類
//同xiaozou
public class UDPSocketTianSendthread implements Runnable{
byte[] ibuf = new byte[1024];
String message;
Scanner scanner = new Scanner(System.in);
DatagramPacket tianPacket;
{
try {
tianPacket = new DatagramPacket(ibuf, ibuf.length, InetAddress.getByName("127.0.0.1"), 8088);
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
DatagramSocket ds;
{
try {
ds = new DatagramSocket(8089, InetAddress.getByName("127.0.0.1"));
} catch (SocketException | UnknownHostException e) {
e.printStackTrace();
}
}
@Override
public void run() {
String txtLine = null;
try{
File file1 = new File("text.txt");
FileInputStream fis = new FileInputStream(file1);
//例項化FileInputStream()物件,並直接傳入已開啟檔案的File物件
InputStreamReader is = new InputStreamReader(fis);
//InputStreamReader用於將位元組流中的位元組碼解碼成字元
BufferedReader br = new BufferedReader(is);
//BufferedReader類從字元輸入流中讀取文字並緩衝字元
//以便有效地讀取字元、陣列和行
//讀取檔案資料,儲存zou的公鑰
while((txtLine=br.readLine())!=null){ //按行讀取字串
while (true) {
System.out.println("請輸入要傳送的資料");
message = scanner.nextLine();
String s1 = null;
try {
//公鑰加密
s1=RSA.encryptByPublicKey(message,txtLine );
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("加密前的資料:" + message);
System.out.println("加密後的資料:" + s1);
tianPacket.setData(s1.getBytes());
try {
assert ds != null;
ds.send(tianPacket);
} catch (IOException e) {
e.printStackTrace();
}
}
}
br.close();
}
catch (FileNotFoundException e1) { //異常處理
System.err.println("File not found!");
}
catch(Exception e2){
e2.printStackTrace();
}
}
}
xiaotian的接收類
UDPSocketTianReceivethread
package xiaotian;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
//同xiaozou
public class UDPSocketTianReceivethread implements Runnable{
DatagramSocket tianSocket;
{
try {
tianSocket = new DatagramSocket(2020);
} catch (SocketException e) {
e.printStackTrace();
}
}
byte[] ibuf = new byte[1024];
DatagramPacket tianPacket = new DatagramPacket(ibuf, ibuf.length);
@Override
public void run() {
while(true){
try {
tianSocket.receive(tianPacket);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("xiaotian:"+new String(tianPacket.getData(),0,tianPacket.getLength()));
}
}
}
結果截圖: