客戶端
package chat;
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
// 客戶端讀取服務器端資訊的執行緒
class ClientReadServer implements Runnable{
private Socket socket;
public ClientReadServer(Socket socket){
this.socket=socket;
}
@Override
public void run() {
// 獲取服務器端輸入流
try {
Scanner scanner=new Scanner(socket.getInputStream());
System.out.println("test");
while(scanner.hasNext()){
// System.out.println("內容:"+scanner.nextLine());
String meg=scanner.nextLine();
System.out.println("服務端回傳:"+meg);
Frame.back(meg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 客戶端向服務器端發送資訊的執行緒
class ClientSendServer implements Runnable{
private static boolean sendFlag = false; //發送標記 點擊發送后變true
private static String msg;
private Socket socket;
public ClientSendServer(Socket socket){
this.socket=socket;
}
@Override
public void run() {
try {
// 獲取服務器端的輸出流
PrintStream printStream=new PrintStream(socket.getOutputStream());
while(true){
if(sendFlag){
printStream.println(msg);
System.out.println("執行緒中run 發送:"+msg);
sendFlag = false; //發送完成后置為false
}
//暫停行程
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// System.out.println("行程進行中!");
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void change(String m,boolean b) {
msg = m;
sendFlag = true;
}
}
public class Client {
public void mainClient () throws IOException{
//1.客戶端連接服務器端,回傳套接字Socket物件
Socket socket=new Socket("127.0.0.1",9527);
//2.創建讀取資訊的執行緒和發送資訊的執行緒
Thread read=new Thread(new ClientReadServer(socket));
Thread send=new Thread(new ClientSendServer(socket));
//3.啟動執行緒
read.start();
send.start();
}
public void send(String mes) {
//發送資訊
System.out.println("準備發送的資料:"+mes);
ClientSendServer.change(mes, true);
}
}
用戶界面
package chat;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.*;
public class Frame extends JFrame {
private static Client client;
private static String backMeg = ""; //服務器回傳訊息
private static JTextArea area;
private static final long serialVersionUID = 1L;
public static void back(String m) {
backMeg = m;
if(backMeg.contains(":")) {
String context = backMeg;
String name ="\n"+ backMeg.split("@")[1].split("\\:")[0] + ":";
context=context.replace('@','\n'); //時間隔開
context=context.replace("$",name);
area.append(context+"\n"); //顯示文本內容增加
}
}
public Frame() {
//JFrame frame = new JFrame("Chat2die"); //創建表單物件
setTitle("ChatRoom"); //標題
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(200, 200, 650, 600); //位置 長寬
setResizable(false); //大小是否可變
Container c = getContentPane(); //獲取表單顏色
c.setBackground(new Color(255, 221, 221,200)); //背景色
c.setLayout(null);
Font f1=new Font("黑體",Font.PLAIN,16);//根據指定字體名稱、樣式和磅值大小,創建一個新 Font,
Font f2=new Font("楷體",Font.BOLD,18);
Font f4=new Font("楷體",Font.BOLD,16);
Font f3=new Font("黑體",Font.PLAIN,14);
//發送文本域
JTextArea jt = new JTextArea(); //文本域
// jt.setText("點擊右邊發送鍵發送"); //提示語
jt.setFont(f4); //設定字體格式
JScrollPane jp = new JScrollPane(jt); //滾動條
jp.setBounds(50, 490, 420, 40); //設定絕對位置
c.add(jp);
//顯示文本域
area = new JTextArea();
area.setFont(f2); //設定字體格式
area.setEditable(false);
JScrollPane jpArea = new JScrollPane(area); //滾動條
jpArea.setBounds(50, 190, 510, 250); //設定絕對位置
c.add(jpArea);
//訊息區
JLabel message = new JLabel();
message.setFont(f2);
message.setText("接收訊息區");
message.setBounds(50, 125, 140, 80);
c.add(message);
//在此輸入您要發送的訊息,點擊右側發送按鈕發送
JLabel sendmessage = new JLabel();
sendmessage.setFont(f2);
sendmessage.setText("在此輸入您要發送的訊息,點擊右側發送按鈕發送");
sendmessage.setBounds(50, 430, 500, 80);
c.add(sendmessage);
//目的IP
JLabel desIp = new JLabel();
desIp.setFont(f2);
desIp.setText("目標IP:");
desIp.setBounds(50, 20, 100, 80);
c.add(desIp);
JTextField desjt = new JTextField();
desjt.setFont(f4);
desjt.setBounds(140, 45, 150, 30);
desjt.setText("127.0.0.1"); //設定默認IP地址
desjt.setEditable(false);
c.add(desjt);
//目的埠
JLabel desPo = new JLabel();
desPo.setFont(f2);
desPo.setText("目標埠:");
desPo.setBounds(320, 20, 100, 80);
c.add(desPo);
JTextField desJtPo = new JTextField();
desJtPo.setFont(f4);
desJtPo.setBounds(405, 45, 150, 30);
desJtPo.setText("0000"); //設定默認埠
c.add(desJtPo);
//你的昵稱
JLabel name = new JLabel();
name.setFont(f2);
name.setText("你的昵稱:");
name.setBounds(50, 75, 100, 80);
c.add(name);
JTextField jtName = new JTextField();
jtName.setFont(f4);
jtName.setBounds(140, 100, 150, 30);
int num = (int) (Math.random()*100);
String t = "未命名用戶["+num+"]";
jtName.setText(t);
c.add(jtName);
//本機埠
JLabel myPo = new JLabel();
myPo.setFont(f2);
myPo.setText("本機埠:");
myPo.setBounds(320, 75, 100, 80);
c.add(myPo);
JTextField jtmyPo = new JTextField();
jtmyPo.setFont(f4);
jtmyPo.setBounds(405, 100, 150, 30);
jtmyPo.setEditable(false);
c.add(jtmyPo);
//系結埠 建立連接
JButton btnBind = new JButton("系結埠 建立連接");
btnBind.setBackground(new Color(255,221,221));
btnBind.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try {
client.mainClient();
//登錄
client.send("userName:"+jtName.getText());
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//暫停行程 等待服務器回傳資料
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("***"+backMeg);
//拿到系結的本機埠號
jtmyPo.setText(backMeg);
}
});
btnBind.setBounds(405, 130, 150, 30);
btnBind.setFont(f3);
c.add(btnBind);
//發送按鈕
JButton btn = new JButton("發送");
btn.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//String sendName = jtName.getText().equals("")?"I AM NULL":jtName.getText();
String context = jt.getText().equals("")?"空空如也":jt.getText();
context=context.replace('\n','$');
jt.setText(""); //清空輸入
jt.requestFocus(); //獲取游標
String sendPort = desJtPo.getText(); //獲取發送埠
if(sendPort.equals("")) return;
String name = jtName.getText();
String sendMes = "P:" + sendPort +"-"+ name + "-" + context;
System.out.println("發送框中的內容是:"+sendMes);
client.send(sendMes);
//暫停行程 等待服務器回傳資料
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//System.out.println("發送后接收到的內容是:"+backMeg);
//area.append(backMeg+"\n"); //文本內容增加
}
});
btn.setBounds(490, 490, 70, 40);
btn.setBackground(new Color(255,221,221));
btn.setFont(f1);
c.add(btn);
setVisible(true); //可見
}
//美化圖示
public static void beautiful() {
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
}catch(Exception e) {
System.out.println(e);
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
beautiful();
client = new Client();
new Frame();
}
}
服務器端
package chat;
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class Server implements Runnable{
private static Map<String,Socket> map=new ConcurrentHashMap<>();
private Socket socket;
public Server(Socket socket){
this.socket=socket;
}
@Override
public void run() {
// 獲取客戶端的輸入流
try {
Scanner scanner=new Scanner(socket.getInputStream());
String msg=null;
while(true){
if(scanner.hasNextLine()){
//處理客戶端輸入的字串
msg=scanner.next();
System.out.println("服務器接收:"+msg);
//用戶登錄流程,注冊用戶的格式為:userName:用戶名
if(msg.startsWith("userName:")){
//將用戶名或者埠號保存在userName中
String userName=msg.split("\\:")[1];
//注冊該用戶
userRegist(userName,socket);
continue;
}
//聊天資訊,輸入的格式為:P:port-userName-聊天資訊
else if(msg.startsWith("P:")&&msg.contains("-")){
//保存需要聊天的目標埠、發送者昵稱、發送的資訊
String port=msg.split("\\:")[1].split("-")[0];
String name = msg.split("\\:")[1].split("-")[1];
String str=msg.split("\\:")[1].split("-")[2];
//發送聊天資訊
privateChat(port,name,str);
continue;
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
//登錄 建立連接
private void userRegist(String userName,Socket socket) throws IOException{
//回傳socket 值
PrintStream printStream=new PrintStream(socket.getOutputStream());
String port=socket.toString().split(",")[1].split("=")[1];
printStream.println(port);
map.put(port,socket); //將 [埠號,套接字] 存一份
System.out.println("[用戶名為"+userName+"][客戶端為"+socket+"]上線了!");
System.out.println("當前在線人數為:"+map.size()+"人");
}
/**
* 私聊流程(利用port取得目標客戶端的Socket物件,從而取得對應輸出流,將私聊資訊發送到指定客戶端)
* @param port 目標客戶端埠號
* @param userName 發送方的用戶名
* @param msg 要發送的資訊
*/
private void privateChat(String port,String userName,String msg) throws IOException {
//1.當前發送方客戶端的用戶名
String curUser=userName;
//2.取得私聊用戶名對應的客戶端
Socket client=map.get(port);
//3.獲取私聊客戶端的輸出流,將私聊資訊發送到指定客戶端
PrintStream printStream=new PrintStream(client.getOutputStream());
Date date = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); //獲得當前時間
String m = formatter.format(date)+"@"+curUser+":"+msg;
System.out.println(formatter.format(date));
System.out.println(m);
printStream.println(m);
//socket.close();
}
}
public class MultiServer {
public static void main(String[] args){
try {
//1.創建服務器端的ServerSocket物件,等待客戶端連接
ServerSocket serverSocket=new ServerSocket(9527);
//2.創建執行緒池,從而可以處理多個客戶端
ExecutorService executorService= Executors.newFixedThreadPool(50);
for(int i=0;i<50;i++){
System.out.println("歡迎來到我的聊天室......");
//3.偵聽客戶端
Socket socket=serverSocket.accept();
System.out.println("有新的朋友加入.....");
//4.啟動執行緒
executorService.execute(new Server(socket));
}
//5.關閉執行緒池
executorService.shutdown();
//6.關閉服務器
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
詳細決議在另一篇給出:
[計算機網路實驗4 - TCP套接字編程 - 點對點聊天 - 分析] - 找不到我吧我獨一無二的博客 - CSDN博客
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/286390.html
標籤:其他
上一篇:基于哈夫曼編碼的C++壓縮程式
