TCP/IP實現本地聊天室(基于Swing)
1程序流程
1.1用戶登錄
客戶端:
1、發送登錄信息:LOGIN|Username
處理USERLISTS命令:所有在線用戶的用戶名 ---(新客戶端)
2、處理新上線用戶信息:ADD|username---(已在線客戶端)
服務器端:
1、得到所有在線用戶信息名稱,發回給客戶端:USERLISTS|user1_user2_user3
2、將當前登錄用戶的信息(用戶名),發送給已經在線的其他用戶:ADD|userName
3、將當前登錄的Socket信息放入Arraylist中
1.2私聊
客戶端:
1、選擇用戶
2、組織一個交互協議,發送到服務器:MSG|SenderName|RecName|MSGInfo
3、接收服務器轉發回的消息
服務器端:
1、解析MSG消息協議字符串,通過RecName用戶名查找,找到目標ServertChat
2、向目標對象發送消息:MSG|SenderName|MSGInfo
1.3 群聊
MSG|Sendername|ALL|MSGInfo
1.4 用戶退出連接(待全部實現)
客戶端:
1、向服務器發送下線消息:OFFLINE|username
2、清空在線用戶列表
3、處理下線用戶信息:DEL|username
刪除用戶列表中的username
服務器端:
1、處理OFFLINE,向所有的其他在線用戶發送用戶下線消息:DEL|username
2、清除ArrayList中的當前用戶信息(ServerChat)
1.5 服務器關閉
客戶端:
1、處理CLOSE命令:界面顯示服務器關閉
2、關閉ClientChat
3、清空在線用戶列表
服務器端:
1、向所有在線用戶發送關閉服務器的信息:CLOSE
2、遍歷Arraylist將其中的每一個ServerChat關閉
3、ArrayList要清空
4、關閉ServerListener
5、關閉ServerSocket
代碼實現
客戶端
//ClientChat.java
package Client;
import java.io.*;
import java.net.*;
public class ClientChat extends Thread {
BufferedReader br=null;
PrintWriter pw=null;
Socket socket=null;
public ClientChat(Socket socket,String sName) {
super(sName);
this.socket=socket;
}
public void run() {
try {
br=new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
pw=new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8")));
//向服務器發送LOGIN信息,格式 : LOGIN|UserName
String sLogin="LOGIN|"+this.getName();
sendMsg(sLogin);
String str="";
while((str=br.readLine())!=null){ //多次發送數據處理的請求
String [] commands=str.split("\\|");
if(commands[0].equals("USERLISTS")){ //格式:LOGIN|UserName
String sUSers=commands[1];
String [] onlineusers=sUSers.split("\\_"); //所有在線用戶名數組
ClientMG.getclientMG().addItems(onlineusers);
}
else if(commands[0].equals("ADD")){//新用戶上線
String sNewUser=commands[1];
ClientMG.getclientMG().addItem(sNewUser);
}
else if(commands[0].equals("MSG")){//接收服務器轉發回的消息,顯示在聊天記錄中 ,格式:MSG|SenderName|MSGInfo
String sendName=commands[1];
String MsgInfo=commands[2];
//
ClientMG.getclientMG().setLogTxt("["+sendName+"]:");
ClientMG.getclientMG().setLogTxt(MsgInfo);
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
try {
if(pw!=null)
pw.close();
if(br!=null)
br.close();
if(socket!=null)
socket.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
// textResult.setText("與服務器斷開連接。");
}
//發送消息
public void sendMsg(String str){
pw.println(str);
pw.flush();
}
}
//ClientForm.java
package Client;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.awt.event.ActionEvent;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;
import javax.swing.JList;
public class ClientForm extends JFrame {
private JPanel contentPane;
public JPanel panel;
public JLabel lblIp;
public JTextField textIP;
public JLabel label;
public JTextField textPort;
public JButton btnLogin;
public JButton btnClose;
public JPanel panel_1;
public JTextArea textSend;
public JButton btnSend;
DefaultListModel<String> itemUsers;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ClientForm frame = new ClientForm();
frame.setVisible(true);
ClientMG.getclientMG().setClientForm(frame);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public ClientForm() {
setTitle("\u5BA2\u6237\u7AEF");
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 514, 608);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
panel = new JPanel();
panel.setBorder(new TitledBorder(null, "\u914D\u7F6E\u4FE1\u606F", TitledBorder.LEADING, TitledBorder.TOP, null, null));
panel.setBounds(10, 10, 488, 67);
contentPane.add(panel);
panel.setLayout(null);
lblIp = new JLabel("IP");
lblIp.setBounds(10, 31, 54, 15);
panel.add(lblIp);
textIP = new JTextField();
textIP.setText("輸入主機IP");
textIP.setBounds(34, 28, 102, 21);
panel.add(textIP);
textIP.setColumns(10);
label = new JLabel("\u7AEF\u53E3");
label.setBounds(146, 31, 54, 15);
panel.add(label);
textPort = new JTextField();
textPort.setText("60000");
textPort.setBounds(178, 28, 45, 21);
panel.add(textPort);
textPort.setColumns(10);
btnLogin = new JButton("\u767B\u5F55");
btnLogin.addActionListener(new BtnLoginActionListener());
btnLogin.setBounds(345, 27, 68, 23);
panel.add(btnLogin);
btnClose = new JButton("\u5173\u95ED");
btnClose.addActionListener(new BtnCloseActionListener());
btnClose.setBounds(410, 27, 68, 23);
panel.add(btnClose);
label_2 = new JLabel("\u7528\u6237\u540D");
label_2.setBounds(229, 31, 54, 15);
panel.add(label_2);
textUser = new JTextField();
textUser.setBounds(269, 28, 66, 21);
panel.add(textUser);
textUser.setColumns(10);
panel_1 = new JPanel();
panel_1.setBorder(new TitledBorder(null, "\u64CD\u4F5C", TitledBorder.LEADING, TitledBorder.TOP, null, null));
panel_1.setBounds(10, 462, 488, 108);
contentPane.add(panel_1);
panel_1.setLayout(null);
btnSend = new JButton("\u53D1\u9001");
btnSend.addActionListener(new BtnSendActionListener());
btnSend.setBounds(407, 75, 71, 23);
panel_1.add(btnSend);
btnSendAll = new JButton("\u7FA4\u53D1");
btnSendAll.addActionListener(new BtnSendAllActionListener());
btnSendAll.setBounds(336, 75, 65, 23);
panel_1.add(btnSendAll);
scrollPane_2 = new JScrollPane();
scrollPane_2.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane_2.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane_2.setBounds(10, 24, 468, 42);
panel_1.add(scrollPane_2);
textSend = new JTextArea();
textSend.setLineWrap(true);
scrollPane_2.setViewportView(textSend);
textSend.setColumns(10);
scrollPane = new JScrollPane();
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setBorder(new TitledBorder(null, "\u804A\u5929\u8BB0\u5F55", TitledBorder.LEADING, TitledBorder.TOP, null, null));
scrollPane.setBounds(10, 87, 286, 378);
contentPane.add(scrollPane);
textLog = new JTextArea();
textLog.setLineWrap(true);
scrollPane.setViewportView(textLog);
scrollPane_1 = new JScrollPane();
scrollPane_1.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane_1.setBorder(new TitledBorder(null, "\u5728\u7EBF\u7528\u6237", TitledBorder.LEADING, TitledBorder.TOP, null, null));
scrollPane_1.setBounds(297, 87, 201, 378);
contentPane.add(scrollPane_1);
itemUsers=new DefaultListModel<String>();
listUsers = new JList(itemUsers);
scrollPane_1.setViewportView(listUsers);
}
// ClientChat sthd;
public JLabel label_2;
public JTextField textUser;
public JScrollPane scrollPane;
public JTextArea textLog;
public JScrollPane scrollPane_1;
public JList listUsers;
public JButton btnSendAll;
public JScrollPane scrollPane_2;
private class BtnLoginActionListener implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
String IP=textIP.getText().trim(); //IP
int port=Integer.parseInt(textPort.getText().trim()); //端口號
if(ClientMG.getclientMG().Connect(IP, port, textUser.getText().trim())){
ClientMG.getclientMG().setLogTxt("已登錄到服務器。");
}
else{
ClientMG.getclientMG().setLogTxt("登錄服務器失敗!");
}
}
}
private class BtnSendActionListener implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
//發送文本框的消息,格式:MSG|SenderName|RecName|MSGInfo
// 1、選擇用戶
// 2、組織一個交互協議,發送到服務器:MSG|SenderName|RecName|MSGInfo
// 3、將發送消息顯示在當前窗口的消息記錄中
if(listUsers.getSelectedIndex()>=0){
String sendName=ClientMG.getclientMG().getClientChat().getName();
String RecName=listUsers.getSelectedValue().toString();
String MSGInfo=textSend.getText().trim();
String MSG="MSG|"+sendName+"|"+RecName+"|"+MSGInfo;
ClientMG.getclientMG().getClientChat().sendMsg(MSG);
//將發送的消息放入消息記錄框中
ClientMG.getclientMG().setLogTxt("[我]:");
ClientMG.getclientMG().setLogTxt(MSGInfo);
//清空發送框
textSend.setText("");
}
}
}
private class BtnCloseActionListener implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
//斷開連接
//從客戶端發送CLose命令到服務 器端,服務端關閉Socket對象,使當前客戶端的br.readLine()返回空值,從而退出While,關閉Socket
// sthd.sendMsg("CLOSE");
}
}
private class BtnSendAllActionListener implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
String sendName=ClientMG.getclientMG().getClientChat().getName();
String RecName="ALL"; //表示群發的功能
String MSGInfo=textSend.getText().trim();
String MSG="MSG|"+sendName+"|"+RecName+"|"+MSGInfo;
ClientMG.getclientMG().getClientChat().sendMsg(MSG);
//將發送的消息放入消息記錄框中
ClientMG.getclientMG().setLogTxt("[我]:");
ClientMG.getclientMG().setLogTxt(MSGInfo);
//清空發送框
textSend.setText("");
}
}
}
//ClientMG.java
package Client;
import java.net.*;
public class ClientMG {
private static final ClientMG clientMG=new ClientMG();
private ClientMG() {}
public static ClientMG getclientMG(){
return clientMG;
}
private ClientForm clientWin;
public void setClientForm(ClientForm c){
clientWin=c;
}
public void setLogTxt(String str){
clientWin.textLog.append(str+"\r\n");
}
ClientChat cChat; //聊天用的Socket所在的線程
public ClientChat getClientChat(){
return cChat;
}
public boolean Connect(String IP,int port,String uName){
Socket socket=null;
try {
socket=new Socket(IP, port); //建立與服務器的連接
cChat=new ClientChat(socket,uName);
cChat.start();
return true;
}catch (Exception e) {
e.printStackTrace();
return false;
}
}
//列表項的操作
//添加所有的在線用戶
public void addItems(String [] susers){
for(int i=0;i<susers.length;i++){
addItem(susers[i]);
}
}
public void addItem(String sNewUser){
clientWin.itemUsers.addElement(sNewUser);
}
}
服務器端
//ServerChat.java
package Server;
import java.io.*;
import java.net.*;
//import SocketGUI.chat.Client.ClientMG;
public class ServerChat extends Thread {
BufferedReader br = null;
PrintWriter pw = null;
Socket socket=null;
public ServerChat(Socket socket) {
this.socket = socket;
}
public void run() {
try {
//實例化br與pw
br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8")));
String str ="";
while((str = br.readLine())!=null){ //循環響應客戶的發送信息//接收客戶端發過來的信息,阻塞命令
String [] commands=str.split("\\|");
if(commands[0].equals("LOGIN")){ //格式:LOGIN|UserName
String sUserName=commands[1];
this.setName(sUserName); //設置當前聊天用戶的名稱
//處理LOGIN,步驟:
//1、得到所有在線用戶信息名稱,發回給客戶端:USERLISTS|user1_user2_user3
ServerMG.getServerMG().getOnlineNames(this);
//2、將當前登錄用戶的信息(用戶名),發送給已經在線的其他用戶:ADD|userName
ServerMG.getServerMG().sendNewUsertoAll(this);;
//3、將當前登錄的Socket信息放入Arraylist中
ServerMG.getServerMG().addOnlielist(this);
}
else if(commands[0].equals("MSG")){ //格式:MSG|SenderName|RecName|MSGInfo
String sendName=commands[1];
String RecName=commands[2];
String MSGInfo=commands[3];
//要判斷出是私聊還是群發
if(RecName.equals("ALL")){
//群發
String sRtnMsg="MSG|"+sendName+"|"+MSGInfo; //回復信息,格式:MSG|SenderName|MSGInfo
ServerMG.getServerMG().sendMsgtoAll(sRtnMsg, this);
ServerMG.getServerMG().setLogTxt(sendName+"發消息["+MSGInfo+"]給"+RecName);
}
else{
//私聊
ServerChat sc=ServerMG.getServerMG().getServerChatByName(RecName); //找到接收目標Socket
if(sc!=null){
String sRtnMsg="MSG|"+sendName+"|"+MSGInfo; //回復信息,格式:MSG|SenderName|MSGInfo
sc.sendMsg(sRtnMsg);
ServerMG.getServerMG().setLogTxt(sendName+"發消息["+MSGInfo+"]給"+RecName);
}
}
}
ServerMG.getServerMG().setLogTxt("客戶端:"+str);
}
} catch (Exception e) {
e.printStackTrace();
}
finally {
try {
if (pw != null)
pw.close();
if (br != null)
br.close();
if (socket != null)
socket.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
public void sendMsg(String str){
pw.println(str);
pw.flush();
}
}
//ServerForm.java
package Server;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.net.*;
import java.io.*;
public class ServerForm extends JFrame {
private JPanel contentPane;
public JPanel panel;
public JLabel label;
public JTextField textPort;
public JButton btnStart;
public JButton btnEND;
public JScrollPane scrollPane;
public JTextArea textLog;
ServerSocket server = null;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ServerForm frame = new ServerForm();
frame.setVisible(true);
ServerMG.getServerMG().setServerForm(frame);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public ServerForm() {
setTitle("\u591A\u4EBA\u804A\u5929\u670D\u52A1\u5668");
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 466);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
panel = new JPanel();
panel.setBorder(new TitledBorder(null, "\u914D\u7F6E\u4FE1\u606F", TitledBorder.LEADING, TitledBorder.TOP, null, null));
panel.setBounds(10, 10, 424, 66);
contentPane.add(panel);
panel.setLayout(null);
label = new JLabel("\u7AEF\u53E3\uFF1A");
label.setBounds(24, 31, 54, 15);
panel.add(label);
textPort = new JTextField();
textPort.setText("60000");
textPort.setBounds(62, 28, 66, 21);
panel.add(textPort);
textPort.setColumns(10);
btnStart = new JButton("\u5F00\u542F\u670D\u52A1");
btnStart.addActionListener(new BtnStartActionListener());
btnStart.setBounds(153, 27, 93, 23);
panel.add(btnStart);
btnEND = new JButton("\u5173\u95ED\u670D\u52A1");
btnEND.addActionListener(new BtnENDActionListener());
btnEND.setBounds(256, 27, 93, 23);
panel.add(btnEND);
scrollPane = new JScrollPane();
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setBorder(new TitledBorder(null, "\u6D88\u606F\u8BB0\u5F55", TitledBorder.LEADING, TitledBorder.TOP, null, null));
scrollPane.setBounds(10, 86, 424, 342);
contentPane.add(scrollPane);
textLog = new JTextArea();
textLog.setLineWrap(true);
scrollPane.setViewportView(textLog);
}
private class BtnStartActionListener implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
int port = Integer.parseInt(textPort.getText().trim()); // //設定端口號
if(ServerMG.getServerMG().CreateServer(port)){
ServerMG.getServerMG().setLogTxt("服務器開啟...");
}
else {
ServerMG.getServerMG().setLogTxt("服務器啟動失敗。");
}
}
}
private class BtnENDActionListener implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
ServerMG.getServerMG().CloseServer();
}
}
}
//ServerListener.java
package Server;
import java.net.*;
public class ServerListener extends Thread {
ServerSocket server=null;
public ServerListener(ServerSocket server) {
this.server=server;
}
public void run() {
Socket socket = null;
try {
while(true){ //監聽多個客戶端的連接
socket = server.accept(); //監聽客戶端連接,客戶端連接后,實例化Socket對象
ServerMG.getServerMG().setLogTxt("客戶端信息:" + socket);
new ServerChat(socket).start(); //開啟新線程用戶與客戶的數據交互
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
//ServerMG.java
package Server;
import java.io.IOException;
import java.net.*;
import java.util.ArrayList;
public class ServerMG {
//單例化類的實現方法
private static final ServerMG servermg=new ServerMG();
private ServerMG() {}
public static ServerMG getServerMG(){
return servermg;
}
//界面操作的相關方法
private ServerForm serverWin;
public void setServerForm(ServerForm s){
serverWin=s;
}
public void setLogTxt(String str){
serverWin.textLog.append(str+"\r\n");
}
ServerSocket server;
public boolean CreateServer(int port){
try {
server = new ServerSocket(port); //創建服務Socket,指定端口號
new ServerListener(server).start();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public void CloseServer(){
try {
//關閉所有在線Sokcet的步驟
if(server!=null)
server.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//在線用戶列表信息
ArrayList<ServerChat> alOnlineList=new ArrayList<ServerChat>();
public synchronized void addOnlielist(ServerChat sc){
//限制同名稱登錄
alOnlineList.add(sc);
}
public void getOnlineNames(ServerChat sc){
if(alOnlineList.size()>0){ //在線用戶列表非空時
String stUser="";
for(int i=0;i<alOnlineList.size();i++){
ServerChat s=alOnlineList.get(i);
stUser+=s.getName()+"_";
}
sc.sendMsg("USERLISTS|"+stUser);
}
}
public void sendNewUsertoAll(ServerChat scurr){
//將當前登錄用戶的信息(用戶名),發送給已經在線的其他用戶
for(int i=0;i<alOnlineList.size();i++){
ServerChat s=alOnlineList.get(i);
s.sendMsg("ADD|"+scurr.getName());
}
}
//使用用戶名查找相對應的Socket所在ServerChat對象
public ServerChat getServerChatByName(String sname){
for(int i=0;i<alOnlineList.size();i++){
ServerChat s=alOnlineList.get(i);
if(s.getName().equals(sname)){
return s;
}
}
return null;
}
//群發消息
public void sendMsgtoAll(String msg,ServerChat sc){
for(int i=0;i<alOnlineList.size();i++){
ServerChat s=alOnlineList.get(i);
if(!s.equals(sc)){ //排除發送者本身
s.sendMsg(msg);
}
}
}
}
只需要啟動ServerForm 和ClientForm 即可運行
智能推薦
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...
猜你喜歡
Linux C系統編程-線程互斥鎖(四)
互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...
統計學習方法 - 樸素貝葉斯
引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...
styled-components —— React 中的 CSS 最佳實踐
https://zhuanlan.zhihu.com/p/29344146 Styled-components 是目前 React 樣式方案中最受關注的一種,它既具備了 css-in-js 的模塊化與參數化優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本。本文是 styled-components 作者之一 Max Stoiber 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...