真沒想到今天又見到了講linux的張老師……他好像要講項目,田老師呢?怪死了,變來變去的,
其實也沒關係,無論是這個張老師,還是田老師,我都沒什麼意見,當然或者是那個講ajax的
王老師也是,都是可以的。
週二、週三、週四主要是說一下項目設計這一塊,但是後面的時間安排並不是很清楚,CS和BS
兩個、CS主要是圖形界面的,BS是一個購物網站設計(郵件羣發和搜索引擎兩部分有點麻煩)
測試驅動的開發,測試代碼編寫……
今天實現局域網多人聊天的點對點的程序,功能不太強也無所謂,關鍵是要完整。
黑盒測試:功能測試(不需要知道源代碼)
白盒測試:函數或是數據流測試(需要知道源代碼)
性能測試:聊天軟件能支持多少人同時在線,響應速度、CPU佔用率、內存消耗等
壓力測試:在極端條件下的性能測試。
迴歸測試:對修復後的做進一步測試
單元測試:驗證某一個函數是否正常工作,函數之間調用是否正確
集成測試:各塊代碼集成在一起,實現一個或者一些功能,驗證代碼集成是否正確
系統測試:驗證子系統之間的協調是否正確。
邊界值測試:輸入的邊界值需要特別重視,還有邊界值的左右兩邊的數值也是需要考慮的
等價類:
里程碑測試:軟件項目衆多階段的其中之一(M1:第一階段、M2:第二階段、Beta:客戶試用)
評審:對測試計劃和測試用例的評審
Bug重現:發現問題後記錄下這個問題,別人能夠根據你的描述重新發現這個bug,如果不能夠發現
的話一般這種bug都不嚴重
BVT測試:版本升級結束後進行的測試
自動化測試:通過測試工具來實現的自動運行的測試。
--------------------------------------------------------------------------
需求分析、概要設計、詳細設計、開發、測試、部署
需求分析:
聊天程序
操作系統:Windows2003 sp1、
數據庫:oracle
開發工具:jbuilder2006
設計工具:powerdesigner12
開發週期:1人/月
功能模塊:
一、聊天服務器模塊
二、聊天客戶端模塊
子模塊:
服務器模塊:
1、註冊模塊
2、登錄處理模塊
3、監聽客戶機連接模塊
4、消息處理模塊(接收消息和發送消息)
客戶機模塊:
1、連接模塊
2、註冊模塊
3、消息處理(接收消息和發送消息)
4、登錄模塊
需求目標:實現點對點發送和接收消息。採用C/S結構。使用swing技術開發
-----------------------------------------------------
概要設計:
監聽客戶機連接模塊:
1、實現連續監聽是否有客戶機連接(多線程)
2、監聽6000端口
3、有客戶機連接:需要與客戶機建立一個連接關係(socket編程或者rmi編程方式)
詳細設計:
監聽客戶機連接模塊:
功能實現:採用socket編程
1、API:採用的是java.net包中的api
java.net.Socket:用來連接到服務器
java.net.ServerSocket:用來建立服務器端的連接
消息傳遞:使用java.net.Socket中的getOutputStream(接收消息)和getInputStream(發送消息)
消息收發部分:
java.io.*:
java.io.PrintWriter:用來封裝一個字節流……使用的構造方法要傳入兩個參數:
PrintWriter(Writer out,boolean autoFlush)實現自動刷新內容
java.io.BufferedReader:封裝字節流
端口監聽部分:
ServerSocket(int port):在構造器中指定
地址處理:
java.net.InetAddress
--------------------------------------------------------------------------
用例圖:
用例:功能模塊
系統、角色、用例
系統:用長方形表示
角色:操作員(小人形狀)
用例:橢圓形狀圖案
管理員、普通用戶
功能用例1:監聽端口(管理員)
功能用例2:管理註冊(管理員)
功能用例3:聊天(普通用戶)
--------------------------------------------
開發
1、圖形界面:服務器端
frame默認的佈局管理器叫做邊界佈局,borderlayout,特點是把整個屏幕分爲
東南西北中五個部分,最多隻能夠放5個組件!如果不指出位置的話默認是居中顯示,
而且是全屏,佔滿剩餘空間
panel:默認的佈局管理器是流佈局,flowlayout,特點是逐行居中顯示……
----------------------------------------------
實現多線程有兩種方法:繼承線程類或是實現可運行接口
一般後者使用更多一些……
package chat ;
public class Test10 extends Thread
{
public Test10(String name)
{
super(name);
}
private int i = 0 ;
public void run()
{
while(true)
{
i = 0 ;
//注意:觀察結果的時候會發現兩個線程是交互運行的!!
if(i >= 500)
{
break ;
}
System.out.println(Thread.currentThread().getName()+"/t"+"i = "+i ++);
}
}
public static void main(String[] args)
{
//通過構造器給線程賦予一個名字
Test10 test = new Test10("第一個線程");
Test10 test01 = new Test10("第二個線程") ;
test01.start() ;
test.start() ;
}
};
----------------------------------------------
如果要繼承接口的話:
package chat ;
public class Test11 implements Runnable
{
private int i = 0 ;
public void run()
{
while(true)
{
i = 0 ;
//注意:觀察結果的時候會發現兩個線程是交互運行的!!
if(i >= 500)
{
break ;
}
System.out.println(Thread.currentThread().getName()+"/t"+"i = "+i ++);
}
}
public static void main(String[] args)
{
Test11 test11 = new Test11() ;
Thread t1 = new Thread(test11) ;
Thread t2 = new Thread(test11) ;
t1.start();
t2.start();
}
};
----------------------------------------------------
關於地址類處理的測試程序:
用到java.net.InetAddress
這個類本身沒有構造器,但是以getLocalHost()爲代表的靜態方法可以取得類的實例。
package chat ;
import java.net.* ;
public class Test12
{
//取得本機的主機名和ip地址
public static void main(String[] args) throws Exception
{
Test12 test12 = new Test12() ;
InetAddress add = InetAddress.getLocalHost() ;
String hostName = add.getHostName() ;
String ip = add.getHostAddress() ;
System.out.println(hostName + "/t" + ip);
//通過對方的名字來得到IP,如果沒有DNS服務器的話……那得在windows的下列目錄中更改:
//C:/WINNT/system32/drivers/etc/hosts
//更改hosts文件,在最後加上下面的類似的ip和對應的名稱
InetAddress add1 = InetAddress.getByName("www.abc.com");
String ip1 = add1.getHostAddress() ;
System.out.println(ip1);
}
}
WINDOWS/system32/drivers/etc/hosts
162.105.81.166 www.abc.com
-------------------------------------------------
Socket:
package chat ;
import java.net.* ;
import java.io.* ;
public class Test13
{
public static void main(String[] args) throws Exception
{
Test13 test13 = new Test13() ;
ServerSocket ss = new ServerSocket(5000) ;
while(true)
{
Socket sk = ss.accept() ;
OutputStream os = sk.getOutputStream() ;
PrintWriter out = new PrintWriter(os,true) ;//自動刷新
out.println("成功連接到服務器!");
//輸出服務器端得到的信息
//BufferedReader br =
// new BufferedReader(new InputStreamReader(sk.getInputStream()));
//String message = br.reakLine() ;
//System.out.println(message) ;
System.out.println(new String(sk.getInetAddress().getHostAddress()) + "已連接到服務器!");
}
}
}
telnet localhost 5000 就可以連接了……
再寫一個客戶端:
package chat ;
import java.net.* ;
import java.io.* ;
public class Test14
{
public static void main(String[] args) throws Exception
{
Test14 test14 = new Test13() ;
Socket ss =
new Socket(InetAddress.getByName("www.rh1.com").getHostAddress(),5000) ;
InputStream is = sk.getInputStream() ;
BufferedReader br = new BufferedReader(new InputStreamReader(is)) ;//字節流包裝成字符流
String message = br.readLine() ;
System.out.println(message);
//PrintWriter out = new PrintWriter(sk.getOutputStream(),true) ;
//out.print(new String(sk.getInetAddress().getAddress()) + "已經連接到服務器!!" );
}
}
==========================================================================================
上面的代碼有些亂,整理一下:
Socket服務器端代碼:
package test;
import java.net.* ;
import java.io.* ;
public class TestSocket {
public TestSocket() {
}
public static void main(String[] args) throws Exception
{
TestSocket test13 = new TestSocket() ;
ServerSocket ss = new ServerSocket(5000) ;
while(true)
{
Socket sk = ss.accept() ;
OutputStream os = sk.getOutputStream() ;
PrintWriter out = new PrintWriter(os,true) ;//自動刷新
out.println("成功連接到服務器!");
System.out.println(new String(sk.getInetAddress().getHostAddress()) + "已連接到服務器!");
}
}
}
------------------
Socket服務器端代碼:
package test;
import java.net.* ;
import java.io.* ;
public class SocketClient {
public SocketClient() {
}
public static void main(String[] args) throws Exception{
SocketClient socketclient = new SocketClient();
Socket ss = new Socket(InetAddress.getByName("localhost").getHostAddress(),5000) ;
//注意上面的getByName中的字符串也應該在hosts中進行響應的處理……
InputStream is = ss.getInputStream() ;
BufferedReader br = new BufferedReader(new InputStreamReader(is)) ;//字節流包裝成字符流
String message = br.readLine() ;
System.out.println(message);
}
}
=====================================================================
啓動服務器按鈕:
使用內部類實現功能
ServerSocket ss;
Socket sk;
int port = 5000;
PrintWriter out;
BufferedReader br;
public class StartServer extends Thread {
//ss = new Short()
//int a = 100;
//();
public void run(){
try {
ss = new ServerSocket(port);
while (true){
sk = ss.accept();
text.append("" + sk.getInetAddress().getHostAddress() + " 已連接到服務器!");
out = new PrintWriter(sk.getOutputStream(),true);
out.println("成功連接到服務器!");
br = new BufferedReader(new InputStreamReader(sk.getInputStream()));
}
}catch(Exception e){
e.printStackTrace();
}
}
}
//“啓動服務器”按鈕的代碼
public void jButton1_actionPerformed(ActionEvent e)
{
StartServer startServer = new StartServer() ;
startServer.start() ;
}
這樣先啓動這個圖形化界面,然後單擊啓動按鈕,再啓動剛纔的客戶端測試代碼
就可以看到文本框中的提示信息了!!
-----------------------------------------------------------
下面改一下客戶端程序:(注意:客戶端的圖形界面和服務器端的圖形界面完全一樣!)
點擊“連接按鈕”後,進行連接
import java.io.* ;
import java.net.* ;
Socket sk ;
int port = 5000 ;
PrintWriter out ;
BufferedReader br ;
String message1 = "" ;
public void jButton1_actionPerformed(ActionEvent e)
{
String add = address.getText();
try
{
sk = new Socket(add,port);
br = new BufferedReader(new InputStreamReader(sk.getInputStream()));
text.append(br.readLine()) ;
}
catch(Exception ee)
{
ee.printStackTrace() ;
}
}
這樣先啓動服務器圖形界面上的啓動按鈕,然後再單擊客戶端上面的連接按鈕就可以看到效果了。
=========================================================================
下面來看看接收和發送消息:
接收是個服務器監聽的過程,必須做成死循環
發送過程很簡單……點擊發送按鈕就可以了……
//無論是服務器端還是客戶端的發送按鈕事件都這麼寫
public void jButton2_actionPerformed(ActionEvent e)
{
out.print(message.getText());
text.append(message.getText());
}
服務器端的多線程類還是定義成內部類:
BufferedReader br =
public class Rev extends Thread
{
public void run()
{
try
{
String content = "" ;
while(!content.equals("Exit!"))
{
if(br == null) return ;
content = br.readLine() ;
text.append(content + "/n")
}
}
catch(Exception ee)
{
ee.printStackTrace() ;
}
}
}
===================================================================
===================================================================
===================================================================
下面的代碼可能有一些問題在裏面…………………………所以…………………………
老師寫的代碼:
服務器界面的Frame:
package chat;
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import java.awt.Color;
import javax.swing.UIManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.*;
import java.io.*;
public class Frame5 extends JFrame {
JPanel contentPane;
BorderLayout borderLayout1 = new BorderLayout();
JPanel jPanel1 = new JPanel();
JPanel jPanel2 = new JPanel();
JScrollPane jScrollPane1 = new JScrollPane();
JTextArea text = new JTextArea();
JButton jButton1 = new JButton();
JTextPane jTextPane1 = new JTextPane();
BorderLayout borderLayout2 = new BorderLayout();
JPanel jPanel3 = new JPanel();
JTextArea message = new JTextArea();
JLabel jLabel1 = new JLabel();
JButton jButton2 = new JButton();
public Frame5() {
try {
setDefaultCloseOperation(EXIT_ON_CLOSE);
jbInit();
} catch (Exception exception) {
exception.printStackTrace();
}
}
/**
* Component initialization.
*
* @throws java.lang.Exception
*/
private void jbInit() throws Exception {
contentPane = (JPanel) getContentPane();
contentPane.setLayout(borderLayout1);
this.setResizable(false);
setSize(new Dimension(400, 300));
setTitle("Frame Title");
jButton1.setText("啓動服務器");
jButton1.addActionListener(new Frame5_jButton1_actionAdapter(this));
jTextPane1.setText("jTextPane1");
jPanel2.setLayout(borderLayout2);
message.setRows(5);
jLabel1.setText("輸入要發送的消息:");
jButton2.setText("發送");
jButton2.addActionListener(new Frame5_jButton2_actionAdapter(this));
text.setBackground(Color.cyan);
contentPane.add(jPanel1, java.awt.BorderLayout.NORTH);
jPanel1.add(jButton1);
contentPane.add(jPanel2, java.awt.BorderLayout.SOUTH);
contentPane.add(jScrollPane1, java.awt.BorderLayout.CENTER);
jScrollPane1.getViewport().add(text);
jPanel3.add(jLabel1);
jPanel3.add(jButton2);
jPanel2.add(jPanel3, java.awt.BorderLayout.CENTER);
jPanel2.add(message, java.awt.BorderLayout.NORTH);
}
ServerSocket ss;
Socket sk;
int port = 5000;
PrintWriter out;
BufferedReader br = null;
public class StartServer extends Thread {
//ss = new Short()
//int a = 100;
//();
public void run(){
try {
ss = new ServerSocket(port);
while (true){
sk = ss.accept();
text.append("" + sk.getInetAddress().getHostAddress() + " 已連接到服務器!/n");
out = new PrintWriter(sk.getOutputStream(),true);
out.println("成功連接到服務器!/n");
br = new BufferedReader(new InputStreamReader(sk.getInputStream()));
if (br == null){
System.out.println("ssssssssssssssssssssssssssssssssssssss");
}
Rev rev = new Rev();
rev.start();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
public class Rev extends Thread {
public void run(){
try {
String content = "";
while (!content.equals("Exit!")){
if (br == null){
System.out.println("br is null");
return;
}
content = br.readLine();
System.out.println(content);
text.append(content + "/n");
}
}catch(Exception ee){
ee.printStackTrace();
}
}
}
public void jButton1_actionPerformed(ActionEvent e) {
StartServer startServer = new StartServer();
startServer.start();
//Rev rev = new Rev();
//rev.start();
}
public void jButton2_actionPerformed(ActionEvent e) {
out.print(message.getText());
text.append(message.getText());
}
}
class Frame5_jButton2_actionAdapter implements ActionListener {
private Frame5 adaptee;
Frame5_jButton2_actionAdapter(Frame5 adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.jButton2_actionPerformed(e);
}
}
class Frame5_jButton1_actionAdapter implements ActionListener {
private Frame5 adaptee;
Frame5_jButton1_actionAdapter(Frame5 adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.jButton1_actionPerformed(e);
}
}
客戶端的Frame:
package chat;
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JButton;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.*;
public class Frame6 extends JFrame {
JPanel contentPane;
BorderLayout borderLayout1 = new BorderLayout();
JPanel jPanel1 = new JPanel();
JScrollPane jScrollPane1 = new JScrollPane();
JLabel jLabel1 = new JLabel();
JTextField address = new JTextField();
JButton jButton1 = new JButton();
JTextArea text = new JTextArea();
JPanel jPanel2 = new JPanel();
BorderLayout borderLayout2 = new BorderLayout();
JPanel jPanel3 = new JPanel();
JTextArea message = new JTextArea();
JLabel jLabel2 = new JLabel();
JButton jButton2 = new JButton();
public Frame6() {
try {
setDefaultCloseOperation(EXIT_ON_CLOSE);
jbInit();
} catch (Exception exception) {
exception.printStackTrace();
}
}
/**
* Component initialization.
*
* @throws java.lang.Exception
*/
private void jbInit() throws Exception {
contentPane = (JPanel) getContentPane();
contentPane.setLayout(borderLayout1);
setSize(new Dimension(400, 300));
setTitle("Frame Title");
jLabel1.setText("服務器IP地址:");
address.setColumns(15);
jButton1.setText("連接");
jButton1.addActionListener(new Frame6_jButton1_actionAdapter(this));
text.setBackground(Color.cyan);
text.setEditable(false);
jPanel2.setLayout(borderLayout2);
message.setRows(5);
jLabel2.setText("輸入要發送的消息:");
jButton2.setText("發送");
jButton2.addActionListener(new Frame6_jButton2_actionAdapter(this));
jPanel1.add(jLabel1);
jPanel1.add(address);
jPanel1.add(jButton1);
contentPane.add(jScrollPane1, java.awt.BorderLayout.CENTER);
jScrollPane1.getViewport().add(text);
contentPane.add(jPanel1, java.awt.BorderLayout.NORTH);
contentPane.add(jPanel2, java.awt.BorderLayout.SOUTH);
jPanel2.add(jPanel3, java.awt.BorderLayout.SOUTH);
jPanel3.add(jLabel2);
jPanel3.add(jButton2);
jPanel2.add(message, java.awt.BorderLayout.NORTH);
}
Socket sk;
int port = 5000;
PrintWriter out;
BufferedReader br;
String message1 = "";
public void jButton1_actionPerformed(ActionEvent e) {
String add = address.getText();
try {
sk = new Socket(add,port);
br = new BufferedReader(new InputStreamReader(sk.getInputStream()));
text.append(br.readLine());
out = new PrintWriter(sk.getOutputStream(),true);
Rev rev = new Rev();
rev.start();
}catch(Exception ee){
}
}
public class Rev extends Thread {
public void run(){
try {
String content = "";
while (!content.equals("Exit!")){
if (br == null){
System.out.println("br is null");
return;
}
content = br.readLine();
System.out.println(content);
text.append(content + "/n");
}
}catch(Exception ee){
ee.printStackTrace();
}
}
}
public void jButton2_actionPerformed(ActionEvent e) {
out.print(message.getText());
text.append(message.getText());
}
}
class Frame6_jButton2_actionAdapter implements ActionListener {
private Frame6 adaptee;
Frame6_jButton2_actionAdapter(Frame6 adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.jButton2_actionPerformed(e);
}
}
class Frame6_jButton1_actionAdapter implements ActionListener {
private Frame6 adaptee;
Frame6_jButton1_actionAdapter(Frame6 adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.jButton1_actionPerformed(e);
}
}