网络基础

TCP/IP

TCP

UDP

IP

端口



java网络开发

Socket套接字


网络应用的模式


C/S 客户端对服务器端

客户端都是根据需要制定的有特定的传输协议

可以为用户提供更准确的需要,更好的效果,

但是对于更新和维护来讲,需要影响用户所以维护和更新是弊端


B/S 浏览器对服务器端

通信协议一致的特殊C/S结构应用



服务端创建一个

ServerSocket 服务器端套接字

    调用accept()方法来等待客户端来连接

        是一个阻塞方法直到一个端口端连接否则该方法一直阻塞 若一个客户端连接了会返回该客户端的Socket



客户端

 创建一个Socket 请求与服务端建立连接

Socket

服务端接收客户端的连接请求,同时创建一个新的Socket与客户端建立连接,服务端继续等待新的请求




ServerSocket

Socket

InetAddress


package se.day001;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * Server 
 *
 */
public class Server {
	private ServerSocket server;
	
	
	public static void main(String[] args) throws Exception{
		//实例化服务端实例
		Server server = new Server();
		//初始化ServerSocket 端口7890
		server.server = new ServerSocket(7788);
		//监控7890,等待Client的连接,返回刚刚连接的Client的Socket,这个方法是一个阻塞方法
		System.out.println("servers start waiting");
		Socket socket = server.server.accept();
		System.out.println("1 client coming");
		InputStream in = socket.getInputStream();
		//将字节输人流庄伟缓冲字符输入流,用于一次读取一行数据
		//
		InputStreamReader reader = new InputStreamReader(in);
		BufferedReader br = new BufferedReader(reader);
		System.out.println(br.readLine());
	}
}
package se.day001;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 
 * Client
 */
public class Client {
	private Socket socket;

	
	public static void main(String[] args) throws Exception{
		Client client = new Client();
		//实例化一个Socket ,指定server ip&port
		client.socket = new Socket("127.0.0.1",7788);
		//通过Socket创建输出流,用于向服务器端发送信息
		OutputStream out = client.socket.getOutputStream();
		PrintWriter pw = new PrintWriter(out,true);
		pw.println("hi,server I am client");
	}
}






最简单的聊天器

package Mon;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class Server {
	private ServerSocket server;
	public Server(int port) throws IOException{
		try {
			System.out.println("初始化服务端");
			server = new ServerSocket(port);
			System.out.println("初始化服务端完成");
		} catch (IOException e) {
			System.out.println("server初始化端口失败");
			e.printStackTrace();
			throw e;
		}
		
		
	}
	//服务端开始工作的方法
	public void start(){
		try {
			System.out.println("等待客户端连接");
			Socket socket = server.accept();
			System.out.println("客户端已经连接");
			PrintWriter pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(),"utf-8"),true);
			pw.println("我的服务器");
			Scanner sc =new Scanner(System.in);
			while(true){
				pw.println(sc.nextLine());
			}
			
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	
	public static void main(String[] args){
		try {
			Server server = new Server(33332);
			server.start();
		} catch (IOException e) {
			System.out.println("server start error");
			e.printStackTrace();
		}
	}
	
}


package Mon;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client {
	private Socket socket;
	public Client() throws IOException{
		try {
			//创建Socket 对象时 就会尝试根据给定的地址与端口连接服务器 所以该对象创建成功说明与服务端连接正常
			System.out.println("初始化客户端");
			socket = new Socket("127.0.0.1",33332);
			System.out.println("初始化客户端成功");
		} catch (UnknownHostException e) {
			System.out.println("端口异常");
			e.printStackTrace();
		} catch (IOException e) {
			System.out.println("其他的连接异常");
			e.printStackTrace();
			throw e;
		}
	}
	
	public void start(){
		try {
			InputStreamReader isr = new InputStreamReader(socket.getInputStream(),"utf-8");
			BufferedReader br  = new BufferedReader(isr);
			String str = null;
			while((str= br.readLine())!=null){
				System.out.println(str);
			}
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}
	
	public static void main(String[] args){
		Client client;
		try {
			client = new Client();
			client.start();
		} catch (IOException e) {
			System.out.println("客户端初始化失败");
			e.printStackTrace();
		}
	}
}




多客户端

package Mon;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Server {
	private ServerSocket server;
	private ExecutorService ThreadPool;

	public Server(int port) throws IOException {
		try {
			System.out.println("初始化服务端");
			server = new ServerSocket(port);
			ThreadPool = Executors.newCachedThreadPool();
			System.out.println("初始化服务端完成");
		} catch (IOException e) {
			System.out.println("server初始化端口失败");
			e.printStackTrace();
			throw e;
		}

	}

	// 服务端开始工作的方法
	public void start() {
		try {
			while (true) {
				System.out.println("等待客户端连接");
				Socket socket = server.accept();
				Runnable handlerIn = new ClientHandlerIn(socket);
				Runnable handlerOut = new ClientHandlerOut(socket);
				ThreadPool.execute(handlerIn);
				ThreadPool.execute(handlerOut);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		try {
			Server server = new Server(33332);
			server.start();
		} catch (IOException e) {
			System.out.println("server start error");
			e.printStackTrace();
		}
	}

	class ClientHandlerIn implements Runnable {
		private Socket socket;

		public ClientHandlerIn(Socket socket) {
			this.socket = socket;
		}

		@Override
		public void run() {
			try {
				PrintWriter pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "utf-8"), true);
				InputStreamReader isr = new InputStreamReader(socket.getInputStream(), "utf-8");
				BufferedReader br = new BufferedReader(isr);
				String str = null;
				while ((str = br.readLine()) != null) {
					System.out.println(socket.getInetAddress().getHostName() + ":" + socket.getPort() + ":" + str);
					pw.println(str);

				}
				// linux 客户断开
				// socket.close();
			} catch (Exception e) {
				// 在windows 中客户端报错通常是因为客户端断开了连接

				// e.printStackTrace();
			} finally {
				try {
					if (socket != null) {
						socket.close();
					}
				} catch (IOException e) {
					// 不需要在处理了
				}
				System.out.println("一个人下线了");

			}
		}
	}

	class ClientHandlerOut implements Runnable {
		private Socket socket;

		public ClientHandlerOut(Socket socket) {
			this.socket = socket;
		}

		@Override
		public void run() {
			try {
				PrintWriter pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "utf-8"), true);
				Scanner sc = new Scanner(System.in);
				while (true) {
					pw.println(sc.nextLine());
				}
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				try {
					socket.close();
				} catch (IOException e) {
				}
			}
		}
	}
}


package Mon;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class Client2 {
	private Socket socket;

	public Client2() throws IOException {
		try {
			// 创建Socket 对象时 就会尝试根据给定的地址与端口连接服务器 所以该对象创建成功说明与服务端连接正常
			System.out.println("初始化客户端");
			socket = new Socket("127.0.0.1", 33332);
			System.out.println("初始化客户端成功");
		} catch (UnknownHostException e) {
			System.out.println("端口异常");
			e.printStackTrace();
		} catch (IOException e) {
			System.out.println("其他的连接异常");
			e.printStackTrace();
			throw e;
		}
	}

	public void start() {
		Runnable outRunnable = new Out(socket);
		Runnable inRunnable = new In(socket);
		new Thread(outRunnable).start();
		new Thread(inRunnable).start();
	}

	public void close(Socket socket) throws IOException {
		try {
			if (socket != null) {
				socket.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			socket.close();
		}

	}

	public static void main(String[] args) {
		Client2 client;
		try {
			client = new Client2();
			client.start();
		} catch (IOException e) {
			System.out.println("客户端初始化失败");
			e.printStackTrace();
		}
	}

	class Out implements Runnable {
		private Socket socket;

		public Out(Socket socket) {
			this.socket = socket;
		}

		@Override
		public void run() {
			Scanner sc = new Scanner(System.in);
			PrintWriter pw;
			try {
				pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "utf-8"), true);
				while (true) {
					pw.println(sc.nextLine());
				}
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}

		}

	}

	class In implements Runnable {
		private Socket socket;

		public In(Socket socket) {
			this.socket = socket;
		}

		@Override
		public void run() {
			InputStreamReader isr;
			try {
				isr = new InputStreamReader(socket.getInputStream(), "utf-8");
				BufferedReader br = new BufferedReader(isr);
				String str = null;
				while ((str = br.readLine()) != null) {
					System.out.println(str);
				}
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}

		}
	}
}













UDP


DatagramPacket

    UDP数据报基于IP建立的每台主机有65536个端口号可以使用,数据报中字节数限制为65536-8

构造接收包 

    DatagramPacket(byte[] buf , int length)

    将数据包中length长的数据装进buf数组

    

    DatagramPacket(byte[] buf,int offset,int length)

    将数据包中从offset开始 length长的数据装进buf数组

   

构建发送包

    DatagramPacket(byte[] buf,int length,InetAddress serverAddress,int serverPort)

    从buf数组中,取出length长的数据创建数据包对象,目标是clienAddress地址,clientPort端口,通常用来发送数据给客户端

    DatagramPacket(byte[] buf,int offset,int length,InetAddress serverAddress , int serverPort)

    从buf数组中,取出offset开始的length长的数据创建数据包对象,目标是clientAddress地址 clientPort端口 通常用来发送数据给客户端


服务端:

DatagramSocket 

    用于接收和发送UDP的Socket实例

    DatagramSocket(int port)

    创建实例并固定监听port端口的报文,通常用于服务端


    receive(DatagramPacket d)

    接收数据报文到d中,receive方法产生 阻塞


客户端:

    DatagramSocket

    用于接收和发送UDP的Socket实例

    无参的构造方法DatagramSocket()

    通常用于客户端编程他并没有特定监听的端口,仅仅使用一个临时的 程序会让操作系统分配一个永科的端口

    send(DatagramPacket dp)

    该方法用于发送报文dp到目的地址




想服务端发送数据的步骤

创建好一Socket

准备数据

创建数据包

将数据存入包中

将数据包通过socket发送给服务端



接收包的步骤

创建一个Socket

创建一个合适大小的包

通过socket接收数据到包中

拆包取数据


package com.stevezong.mon2ice4udp;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class Server {

	// 服务端启动方法
	public void start() {
		try {
			int port = 8080;
			DatagramSocket socket = new DatagramSocket(port);
			byte[] buf = new byte[50];
			DatagramPacket receivePacket = new DatagramPacket(buf, 50);
			while(true){
				socket.receive(receivePacket);
				
				String str = new String(receivePacket.getData(),"utf-8"); 
				System.out.println(str);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public static void main(String[] args) {
		// 创建服务端
		Server server = new Server();
		// 启动服务端
		server.start();
	}
}


package com.stevezong.mon2ice4udp;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class Client {

	public void start() {
		try {
			DatagramSocket socket = new DatagramSocket();
			String str = "我是客户端1";
			byte[] buf = str.getBytes("utf-8");
			int bufLength = buf.length;
			InetAddress address = InetAddress.getByName("127.0.0.1");
			int port = 8080;
			DatagramPacket sendPakcet = new DatagramPacket(buf, bufLength, address, port);
			socket.send(sendPakcet);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public static void main(String[] arg) {
		Client client = new Client();
		client.start();
	}
}