Java Socket網絡編程

Java Socket網絡編程

計算機網絡中,客戶機與服務器之間進行通訊時,客戶機必須知道服務器的IP地址和端口號。IP地址是標識Internet網絡中的某臺計算機,而端口號則標識着在服務器上運行的某個程序(進程),若是在服務器上運行的程序,沒有端口號,則客戶端的程序就不能找到它,也不能和它進行通訊。必定要清楚,別和電腦上的物理端口號搞混了。 端口號是一個邏輯的地址,用於標識計算機中運行着的應用程序。它能夠是0~65535之間的一個數,0~1023爲系統保留使用,例如http的是80端口等,這些是系統已經分配給默認服務使用的。 當兩個應用程序須要經過網絡通訊時,就可使用IP地址和端口號進行經過,IP地址和端口號組合在一塊兒就是一個Socket(網絡套接字)。套接字分爲服務端的和客戶端的兩種java

1、客戶端套接字

客戶端的套接字用於與服務器端的套接字進行鏈接。其使用方法以下:編程

socket=new Socket("127.0.0.1",2018);緩存

其中127.0.0.1標識服務器端的IP地址,2018標識服務器端應用程序的端口號。在創建套接字的過程當中,可能會發生IOException異常,要注意進行處理。服務器

2、服務器端套接字

客戶端與服務器端通訊時,服務器端負責提供服務,客戶端經過Socket向服務器端請求服務。所以,在服務器端也必須有相應的套接字與客戶端進行鏈接。使用以下:網絡

try {
     serverSocket=new ServerSocket(2018);
     socket=serverSocket.accept();
} catch (IOException e) {
     e.printStackTrace();
}

ServerSocket的構造方法中,只有一個參數,即Port號,須要注意的是,服務器端的Port號必須與客戶端的相同。多線程

當調用ServerSocket的accept()方法時,會返回一個客戶端套接字對象,即Socket對象。該對象在客戶端與服務端鏈接的過程當中,將駐留在服務器的內存中,咱們經過它就能夠與客戶端進行數據的傳輸。app

3、客戶端與服務端通訊的簡單實現

客戶端與服務端通訊時,首先服務端要在相應的端口進行監聽,等待客戶端的鏈接請求。而後在客戶端請求時,接受客戶端的請求,而後進行通訊。首先是服務端。代碼以下:socket

package socket.demo2;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class MyServerFrame extends JFrame{
    //接收客戶端發送的消息
    private JTextArea allMessage=new JTextArea(8,20);
    // 輸入發送給客戶端的消息
    private JTextField sendMessage=new JTextField(20);
    //消息發送按鈕
    private JButton sendBtn=new JButton("發送");
    private JButton startServer=new JButton("開始服務器");

    private ServerSocket serverSocket=null;//服務器端Socket
    private BufferedReader in=null;//用於接收客戶端發送的數據
    private BufferedWriter out=null;//用於發送數據給客戶端
    private Socket socket=null;//客戶端鏈接對象

    private int port;
    public void setPort(int port){
        this.port=port;
    }
    public MyServerFrame(){
        init();
    }
    private void init(){
        setTitle("服務端");
        setLayout(new BorderLayout());

        //開始服務器按鈕單擊事件
        startServer.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    serverSocket=new ServerSocket(port);
                    socket=serverSocket.accept();
                    new receiverMsgThread().start();//啓動線程接收客戶端數據
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        });
        //發送按鈕單擊事件
        sendBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    out=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                    out.write(sendMessage.getText());
                    out.newLine();
                    out.flush();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }

            }
        });

        //將組件添加到窗體中
        JPanel panel=new JPanel();
        panel.add(startServer);
        panel.add(sendMessage);
        panel.add(sendBtn);

        add(allMessage,BorderLayout.CENTER);
        add(panel,BorderLayout.SOUTH);

        //配置窗體
        setSize(500,300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }

    //接收信息線程
    class receiverMsgThread extends Thread{
        public void run(){
            try {
                in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String str=null;
                while (true){
                    str=in.readLine()+"\n";
                    allMessage.append("客戶端說:"+str);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        MyServerFrame myServerFrame=new MyServerFrame();
        myServerFrame.setPort(12345);
    }
}

客戶端代碼以下:ide

package socket.demo2;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.Socket;

public class MyClientFrame extends JFrame{
    //接收客戶端發送的消息
    private JTextArea allMessage=new JTextArea(8,20);
    // 輸入發送給客戶端的消息
    private JTextField sendMessage=new JTextField(20);
    //消息發送按鈕
    private JButton sendBtn=new JButton("發送");
    private JButton connServer=new JButton("鏈接服務器");
    private Socket socket=null;
    private BufferedReader in=null;
    private BufferedWriter out=null;

    public MyClientFrame(){
        init();
    }
    private void init(){
        setTitle("客戶端");
        setLayout(new BorderLayout());

        //鏈接服務器按鈕單擊事件
        connServer.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    socket=new Socket("127.0.0.1",12345);
                    System.out.println("鏈接成功");
                    new receiverMsgThread().start();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        });
        //發送按鈕單擊事件
        sendBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    out=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                    out.write(sendMessage.getText());
                    out.newLine();
                    out.flush();
                    System.out.println("222");
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        });

        //將組件添加到窗體中
        JPanel panel=new JPanel();
        panel.add(connServer);
        panel.add(sendMessage);
        panel.add(sendBtn);

        add(allMessage,BorderLayout.CENTER);
        add(panel,BorderLayout.SOUTH);

        //配置窗體
        setSize(500,300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }

    class receiverMsgThread extends Thread{
        public void run(){
            InputStream is=null;
            BufferedReader br=null;
            String str=null;
            try {
                is=socket.getInputStream();
                br=new BufferedReader(new InputStreamReader(is));
                while(true){
                    str=br.readLine()+"\n";
                    allMessage.append("服務器說:"+str);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println("客戶端");
        }
    }

    public static void main(String[] args) {
        new MyClientFrame();
    }
}

程序運行界面以下:this

目前爲止,服務端只能與一個客戶端進行通訊。在編寫的過程當中,因爲對BufferedReader類,以前並不瞭解,所以在編寫的過程當中,遇到了很大的問題,致使走了不少的彎路。最後經過查閱其文檔,解決了問題。主要是由於其readLine()方法,在發送數據時,它是以回車符做爲結束的,不然它不會結束,從而致使後續的操做沒法完成,所以在發送數據時,必定要注意,代碼以下:

out=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
out.write(sendMessage.getText());//這個只是將數據寫入到緩存中,並不真正進行發送
out.newLine();//這是一個新行,標識傳輸數據的結束,這點必定要注意
out.flush();//這個是將緩存中的數據進行發送

4、服務端的改進

以上程序代碼中,服務器只能接收一個客戶端的鏈接,下面對服務器端進行改進,實現多個客戶端的鏈接。

思想以下:採用多線程方式,每個客戶端鏈接時,啓動一個線程負責該客戶端的通訊,將產生的客戶端Socket放入到一個集合中,而後,當客戶端發送數據時,服務器端將收到的數據轉發給全部的客戶端。服務端修改後的代碼以下;

package socket.demo2;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class MyServerFrame extends JFrame{
    //保存客戶端的Socket,用於向全部的客戶端進行數據的轉發。
    private static List<Socket> clients=new ArrayList<Socket>();
    //接收客戶端發送的消息
    private JTextArea allMessage=new JTextArea(8,20);
    // 輸入發送給客戶端的消息
    private JTextField sendMessage=new JTextField(20);
    //消息發送按鈕
    private JButton sendBtn=new JButton("發送");
    private JButton startServer=new JButton("開始服務器");

    private ServerSocket serverSocket=null;//服務器端Socket
    private BufferedReader in=null;//用於接收客戶端發送的數據
    private BufferedWriter out=null;//用於發送數據給客戶端
    private Socket socket=null;//客戶端鏈接對象

    private int port;
    public void setPort(int port){
        this.port=port;
    }
    public MyServerFrame(){
        init();
    }
    private void init(){
        setTitle("服務端");
        setLayout(new BorderLayout());

        //開始服務器按鈕單擊事件
        startServer.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                startServer.setEnabled(false);
                //啓動鏈接線程
                try {
                    serverSocket=new ServerSocket(port);
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                new connClient().start();
            }
        });
        //發送按鈕單擊事件
        sendBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    for(Socket s:clients){
                        out=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
                        out.write(sendMessage.getText());
                        out.newLine();
                        out.flush();
                    }
                } catch (IOException e1) {
                    e1.printStackTrace();
                }

            }
        });

        //將組件添加到窗體中
        JPanel panel=new JPanel();
        panel.add(startServer);
        panel.add(sendMessage);
        panel.add(sendBtn);

        add(allMessage,BorderLayout.CENTER);
        add(panel,BorderLayout.SOUTH);

        //配置窗體
        setSize(500,300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }

    class connClient extends Thread{
        public void run(){
            while(true){
                try {
                    socket=serverSocket.accept();
                    clients.add(socket);
                    new sendMsgToClients(socket).start();
                    new receiverMsgThread().start();//啓動線程接收客戶端數據
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    //接收信息線程
    class receiverMsgThread extends Thread{
        public void run(){
            try {
                in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String str=null;
                while (true){
                    str=in.readLine()+"\n";
                    allMessage.append("客戶端說:"+str);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    class sendMsgToClients extends Thread{
        private Socket clientSocket;
        public sendMsgToClients(Socket clientSocket){
            this.clientSocket=clientSocket;
        }
        public void run(){
            //首先接收客戶端發送過來的信息,
            //而後向客戶端,進行信息的轉發。
            try {
                while(true){
                    in=new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                    String str=in.readLine();
                    for(Socket s:clients){
                        out=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
                        out.write(str);
                        out.newLine();
                        out.flush();
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                clients.remove(socket);
            }
        }
    }

    public static void main(String[] args) {
        MyServerFrame myServerFrame=new MyServerFrame();
        myServerFrame.setPort(12345);
    }
}
相關文章
相關標籤/搜索