在Java中,基于TCP協定實作的網絡通信類有兩個:Socket類和ServerSocket類,用戶端使用的是Socket類,伺服器端使用的是ServerSocket類。使用它們可以友善的完成資訊的互動,用戶端與伺服器端的連接配接,由伺服器端向用戶端提供服務。
Socket類建立連接配接的過程是:首先在伺服器端指定一個用來等待連接配接的端口建立一個ServerSocket執行個體,然後在用戶端通過規定一個主機與端口号建立一個Socket執行個體,連接配接到伺服器上。ServerSocket類的accept方法使伺服器處于阻塞狀态,等待使用者請求。
Scoket通信程式基本過程(4個步驟):
(1).在用戶端和伺服器端建立Scoket/ServerSocket執行個體。
(2).打開連接配接到Socket的輸入/輸出流。
(3).利用輸入/輸出流和Socket。
(4)關閉Socket(I/O流是基于Socket管道的,當Socket關閉時,I/O流也随之關閉)。
Socket連接配接過程如下圖所示:
1.建立Socke連接配接
主要實作代碼:
服務端:
try{
ServerSocket server = new ServerSocket(9000);//伺服器端建立套接字服務
}
catch(IOException e){
//
}
Socket socket = null;
try{
socket = server.accept();//監聽用戶端連接配接
}
catch(IOException e){
//
}
用戶端:
try{
Socket client = new Socket(host,9000);//用戶端建立套接字
}
catch(IOException e){
//
}
2.在用戶端和伺服器端同時打開輸入/輸出流
Socket 提供方法getinputStream()和getOutputStream()來得到對應的輸入/輸出流,進行資料的讀寫操作,方法分别傳回InputStream對象和OutpputStream對象。可以把它們封裝在緩沖流中以提高程式的性能,主要代碼如下所示:
//輸入流
InputStreamReader isr = new InputStreamReader(socket.getInputStream());
BufferedReader br = new BufferedReader(isr);
//輸出流
InputStreamWriter isw = new InputStreamWriter(socket.getOutputStream());
InputStreamReader isr = new InputStreamReader(isw);
3.關閉輸入/輸出流
在用戶端和伺服器端關閉Socket.
範例示範:
建立一個簡單的聊天程式為例示範Socket程式設計,該程式分為用戶端和伺服器端。伺服器端能夠接收到多個連接配接,用戶端可以連接配接伺服器,發送資訊給伺服器端,伺服器接受消息,轉發給所有客戶。
實作結果如下圖所示:
實作代碼:
伺服器端代碼:
server.java
package com.venus.myscoket.server;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Enumeration;
import java.util.Vector;
public class Server {
public Server(int port) throws Exception {//構造函數,參數為端口号
//建立ServerSocket
ServerSocket server = new ServerSocket(port);
//不斷接受客戶資訊
while(true){
//監聽用戶端的連接配接
Socket conn = server.accept();
//将伺服器端的輸入流封裝到DataInputStream類中,該類支援與機器無關的編碼方式
DataInputStream in = new DataInputStream(conn.getInputStream());
//讀取使用者資訊
String who = in.readUTF();
System.out.println("Client+(Ip:"+conn.getInetAddress()+")"+who+"enter!"+"\n");
//每次監聽就建立一個線程
ServerHander cn = new ServerHander(who,conn);
cn.start();
}
}
public static void main(String args[]) throws Exception{
new Server(9013);
}
}
class ServerHander extends Thread{
Socket socket = null;
DataInputStream in = null;
DataOutputStream out = null;
String who = null;
//保護所有的用戶端對象
protected static Vector<ServerHander>clientlist = new Vector<ServerHander>();
public ServerHander(String name,Socket socket) throws IOException {
this.who = name;
this.socket = socket;
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
}
@Override
public void run() {
try {
clientlist.addElement(this);
sendallclient("weclome "+who+" entered");
//無限循環
while(true){
String msg = in.readUTF();
sendallclient(who+" : "+msg);
}
} catch (IOException e) {
System.out.println("client exit or error.");
}finally{
clientlist.removeElement(this);
sendallclient(who+"left !");
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("Connection has been closed");
}
}
}
/**
* 給用戶端傳遞資訊的方法
* @param msg
*/
protected static void sendallclient(String msg){
synchronized (clientlist) {//對用戶端的vector加鎖
Enumeration<ServerHander> allclients = clientlist.elements();
//周遊通路每個用戶端對象
while(allclients.hasMoreElements()){
ServerHander serh = (ServerHander)allclients.nextElement();
try {
serh.out.writeUTF(msg);//向用戶端發送資訊
serh.out.flush();//重新整理輸出流,保證内容輸出
} catch (IOException e) {
// TODO Auto-generated catch block
serh.interrupt();//終端線程
}
}
}
}
}
用戶端代碼:
Client.java
package com.venus.myscoket.server;
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
public ServiceFrame sf;//用戶端窗體
private Socket csocket;//Socket對象
private DataInputStream in;//輸入流
private DataOutputStream out;//輸出流
public static void main(String[] args){
String who="";
//獲得輸出流
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
//輸出提示資訊
System.out.print("please input your name,and then please Enter :");
try {
//讀取登入名
who = in.readLine().trim();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//調用Client構造函數
new Client(who,"172.20.83.37",9013);
}
public Client(String who,String server,int port){
//建立用戶端窗體
sf = new ServiceFrame("簡單聊天");
//添加鍵盤監聽事件
sf.sendFD.addKeyListener(new ActListener(this, sf));
sf.addWindowListener(new ExitListener(this));
try {
//建立Socket對象
csocket = new Socket(server ,port);
//輸入流
in = new DataInputStream(new BufferedInputStream(csocket.getInputStream()));
//輸出流
out = new DataOutputStream(new BufferedOutputStream(csocket.getOutputStream()));
//向輸出流輸出who資訊
out.writeUTF(who);
//重新整理輸出流
out.flush();
while(true){
sf.showTA.append("--"+in.readUTF()+"\n");//在窗體輸出資訊
}
} catch (Exception e) {
System.out.println("Server error!");
this.close();
System.exit(0);
}
}
protected void send(String msg){//輸出資訊
try {
out.writeUTF(msg);
out.flush();
} catch (IOException e) {}
}
protected void close(){
try {
sf.dispose();
out.close();
in.close();
csocket.close();
} catch (IOException e) {}
}
}
class ServiceFrame extends Frame{
protected TextArea showTA;
protected TextField sendFD;
public ServiceFrame(String winnm){
super(winnm);
setLayout(new BorderLayout());
add("North",showTA = new TextArea());
showTA.setEditable(false);
add("South",sendFD = new TextField());
pack();
show();
sendFD.requestFocus();
}
}
class ActListener extends KeyAdapter{
Client client;
ServiceFrame sFrame;
public ActListener(Client c,ServiceFrame sf) {
client = c;
sFrame = sf;
}
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_ENTER){
client.send(sFrame.sendFD.getText());
sFrame.sendFD.setText("");
}
}
}
class ExitListener extends WindowAdapter{
Client client;
public ExitListener(Client c){
client = c;
}
public void windowClosing(WindowEvent e){
client.close();
System.exit(0);
}
}