Socket 通訊入門


1、Socket套接字

  • 網絡上的兩個程序經過一個雙向的通訊您鏈接實現數據交換,這個鏈接的一端稱爲一個socket。
  • java中使用socket完成TCP程序的開發,使用此類方法能夠方便的創建可靠地,雙向的,持續性的,點對點得通信鏈接
  • 在socket的程序開發中,服務器端使用ServerSocket等待客戶端的鏈接,對於java的網絡程序來講,每個客戶端都是用一個socket對象表示。

2、代碼示例

2.1 完成一次服務端與客戶端通訊

  • 用本機的當作服務器與客戶端進行通訊。
  • 服務端等待客戶端的鏈接,在客戶端鏈接後發送數據給客戶端。

Server

package com.rrs.socketserver;

import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import org.junit.Test;

/**
 * @author lzx
 * on 2019/9/25.
 */
public class SocketServer {

	@Test
	public void test01() throws IOException {

		System.out.println("socket server start...");
		ServerSocket serverSocket = new ServerSocket(8888);

		Socket socket = serverSocket.accept();
		System.out.println("檢測到客戶端socket:" + socket);

		OutputStream out = socket.getOutputStream();

		String mString = "Hello Client";
		byte[] bytes = mString.getBytes();

		out.write(bytes);

		socket.shutdownOutput();
		out.close();

	}

}

Client

package com.rrs.sockerclient;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.SocketAddress;

/**
 * Created by lzx on 2019/9/25.
 */
public class SocketClient {


    public static void main(String[] args) throws IOException {

        System.out.println("socket client start...");
        Socket socketClient = null;


        socketClient = new Socket("127.0.0.1", 8888);
        InputStream in = socketClient.getInputStream();
        byte[] bytes = new byte[1024];

        int len = in.read(bytes);

        String msg = new String(bytes, 0, len);

        System.out.println(msg);
    }

}

2.2 完成客戶端到服務端圖片傳輸

Server 服務端等待客戶端發送圖片

package com.rrs.socketserver.server;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

import org.junit.Test;

/**
 * @author lzx
 *
 */
public class ServerPic {

	@Test
	public void serverPic() throws IOException {

		System.out.println("server start...");

		// 建立socket
		ServerSocket server = new ServerSocket(8899);

		// 阻塞式監聽客戶端
		Socket socket = server.accept();

		// 得到輸入流
		InputStream in = socket.getInputStream();

		byte[] buf = new byte[1024];
		int len = 0;

		// 邊讀邊寫
		// 寫到服務端磁盤上

		// 得到文件輸出流
		File file = new File("java.jpg");
		FileOutputStream out = new FileOutputStream(file);

		while ((len = in.read(buf)) != -1) {

			out.write(buf, 0, len);
		}

		System.out.println("圖片接受完畢...");
		
		socket.shutdownInput();
		in.close();
		out.close();
		

	}

}

Client 客戶端發送圖片

package com.rrs.socketserver.client;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

import org.junit.Test;

/**
 * @author lzx
 *
 */
public class ClientPic {

	@Test
	public void clientPic() throws IOException {

		System.out.println("client start...");

		// 建立socket客戶端
		Socket client = new Socket("127.0.0.1", 8899);

		// 從本地讀取文件發送文件(邊讀邊寫)

		// 讀取文件
		File file = new File("D:/Desktop/java.jpg");
		FileInputStream in = new FileInputStream(file);

		// 每次發送1k
		byte[] buf = new byte[1024];

		int len = 0;

		OutputStream out = client.getOutputStream();

		while ((len = in.read(buf)) != -1) {
			out.write(buf, 0, len);
		}
		System.out.println("圖片發送完成...");

		out.close();
		in.close();
		client.shutdownOutput();

	}

}

2.3 完成模擬登陸

Server 服務端

package com.rrs.socketserver.server;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import org.junit.Test;

import com.rrs.socketserver.pojo.User;

/**
 * @author lzx 模擬登陸服務端
 */
public class ServerLogin {

	@Test
	public void serverLogin() throws IOException, ClassNotFoundException {

		System.out.println("Server Start...");

		// 建立服務端socket
		ServerSocket server = new ServerSocket(8800);
		// 阻塞式監聽客戶端socket
		Socket socket = server.accept();

		InputStream in = socket.getInputStream();
		ObjectInputStream stream = new ObjectInputStream(in);

		User user = (User) stream.readObject();
		
		socket.shutdownInput();
		
		
		// 得到輸出流反饋信息
		OutputStream out = socket.getOutputStream();
		
		String msg = "";
		
		if (user.getName().equals("張三") && user.getPassword() == 111111) {

			msg = "登陸成功";
		}else {
			msg = "登陸失敗";
		}
		
		DataOutputStream outputStream = new DataOutputStream(out);
		outputStream.writeUTF(msg);
		
		socket.shutdownOutput();
		outputStream.close();
		out.close();
		stream.close();
		in.close();
		
	}

}

Client 客戶端

package com.rrs.socketserver.client;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

import org.junit.Test;

import com.rrs.socketserver.pojo.User;

/**
 * @author lzx
 *  模擬登陸客戶端
 */
public class ClientLogin {
	
	@Test
	public void  clientLogin() throws UnknownHostException, IOException {
		
		System.out.println("Client Start...");
		// 控制檯輸入用戶名,密碼
		Scanner scan = new Scanner(System.in);
		
		System.out.println("請輸入用戶名:");
		String name = scan.next();
		
		System.out.println("請輸入密碼:");
		int password = scan.nextInt();
		
		User user = new User(name, password);
		
		// 經過socket 傳輸
		Socket client  = new Socket("127.0.0.1", 8800);
		// 獲取輸出流
		OutputStream out = client.getOutputStream();
		ObjectOutputStream stream = new ObjectOutputStream(out);
		
		// 將對象寫入流中
		stream.writeObject(user);
		
		client.shutdownOutput();
		
		// 接受消息
		InputStream in = client.getInputStream();
		DataInputStream inputStream = new DataInputStream(in);
		
		String msg = inputStream.readUTF();
		System.out.println(msg);
		client.shutdownInput();
		
		//關閉資源
		inputStream.close();
		in.close();
		stream.close();
		out.close();
	}

}

2.4 多線程優化服務端程序

  在以上咱們發現,服務端在被客戶端鏈接一次後就結束運行了,那麼咱們服務器在運行起來後是不須要關閉的,咱們可使用多線程來優化咱們的代碼。java

建立一個登陸線程:

package com.rrs.socketserver.thread;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.net.Socket;

import com.rrs.socketserver.pojo.User;

/**
 * @author lzx
 *
 */
public class LoginThread extends Thread {

	private Socket socket;

	private InputStream in;
	private ObjectInputStream stream;
	private OutputStream out;

	public Socket getSocket() {
		return socket;
	}

	public LoginThread() {
		super();
	}

	public void setSocket(Socket socket) {
		this.socket = socket;
	}

	public LoginThread(Socket socket) {
		super();
		this.socket = socket;
	}

	@Override
	public void run() {

		// 得到輸出流反饋信息
		try {
			in = socket.getInputStream();
			stream = new ObjectInputStream(in);

			User user = (User) stream.readObject();

			socket.shutdownInput();

			out = socket.getOutputStream();

			String msg = "";

			if (user.getName().equals("張三") && user.getPassword() == 111111) {

				msg = "登陸成功";
			} else {
				msg = "登陸失敗";
			}

			DataOutputStream outputStream = new DataOutputStream(out);
			outputStream.writeUTF(msg);

			socket.shutdownOutput();
			outputStream.close();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (null != out) {
					out.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if (null != stream) {
					stream.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if (null != in) {
					in.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

}

server 服務端

package com.rrs.socketserver.server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import org.junit.Test;

import com.rrs.socketserver.thread.LoginThread;

/**
 * @author lzx 模擬登陸服務端
 */
public class ServerLogin {

	@Test
	public void serverLogin() throws IOException, ClassNotFoundException {

		System.out.println("Server Start...");

		// 建立服務端socket
		ServerSocket server = new ServerSocket(8800);

		int count = 1;

		while (true) {

			// 阻塞式監聽客戶端socket
			Socket socket = server.accept();
			new LoginThread(socket).start();
			System.out.println("第" + count + "個用戶嘗試登陸...");
			count++;
		}
	}

}

  以上只是一個簡單的入門例子,在實際開發中若是多個用戶都同時訪問服務端則會開啓多個線程形成服務器壓力,所以能夠嘗試使用線程池來優化。服務器

相關文章
相關標籤/搜索