Socket 笔记

一、网络基础知识

1、两台计算机要通过网络进行通信,必须具备:

1)唯一的标识(IP地址);

2)需要共同的语言(协议);

3)辨别不同应用程序(端口号)。

2、了解相关概念

1)IP地址:

每台计算机的唯一标识,用来区分网络中的不同主机,是两台主机进行网络通信必不可少的。2)协议:

(1)TCP/IP协议:目前世界上应用最为广泛的协议。是以TCP和IP为基础的不同层次上多个协议的集合。也称为:TCP/IP协议族  或者  TCP/IP协议栈。(TCP: Transmission Control Protocol -- 传输控制协议;IP :Internet Protocol -- 互联网协议)

3)CP/IP模型(网络分层):

(1)物理层(如网线、网线槽)

(2)数据链路层

(3)网络层

(4)传输层:TCP/IP协议

(5)应用层:HTTP超文本传输协议、FTP文件传输协议、SMTP简单邮件传送协议、Telnet远程登录服务。

4)端口号:

(1)用于区分不同的应用程序;

(2)端口号范围为0-65535,其中0-1023为系统所保留;

(3)IP地址和端口号组成了所谓的Socket,Socket是网络上运行的程序之间双向通信链路的终结点,是TCP和UDP的基础。

(4)常用端口号-- http: 80;  ftp; 21;  telnet; 23。

5)JAVA中得网络支持。针对网络通信的不同层次,Java提供的网络功能有四大类:

(1)InetAddress:用于标识网络上的硬件资源。(IP地址)

(2)URL:统一资源定位符---通过URL可以直接读取或写入网络上得数据。

(3)Sockets:使用TCP协议实现网络通信的Socket相关的类。

(4)Datagram:使用UDP协议,将数据保存在数据报中,通过网络进行通信。

 

二、Java网络相关的API的应用

1InetAddress类

1)InetAddress类没有构造方法,所以不能直接new出一个对象;但可以通过InetAddress类的静态方法获得InetAddress的对象:如

InetAddress.getLocalHost();

InetAddress.getByName();

2)类主要方法:

String - address.getHostName();

String - address.getHostAddress();

public static InetAddress getByName(String host) throws UnknownHostException

// 在给定主机名的情况下确定主机的 IP 地址。主机名可以是机器名(如 "java.sun.com"),也可以是其 IP 地址的文本表示形式

3)InetAddress使用示例代码:

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;

/**
 * InetAddress类的基本使用
 */
public class InetAddressDemo {
	public static void main(String[] args) throws UnknownHostException {
		/*
		 * 获取本地主机信息
		 */
		InetAddress address = InetAddress.getLocalHost();
		System.out.println("主机名称" + address.getHostName());
		System.out.println("IP地址:" + address.getHostAddress());
		byte[] bytes = address.getAddress(); // 以获取字节数组的形式获取地址
		System.out.println("自己数组形式的ip: " + Arrays.toString(bytes));
		System.out.println(address);// 直接输出InetAddress对象
		System.out.println();
		
		/*
		 *  根据机器名获取InetAddresss实例
		 */
		InetAddress address2 = InetAddress.getByName("Moonlight");
		System.out.println("计算机名:" + address2.getHostName());
		System.out.println("IP地址:" + address2.getHostAddress());
		System.out.println();
		
		/*
		 * 根据IP获取InetAddress实例
		 */
		InetAddress address3 = InetAddress.getByName("192.168.1.102");
		System.out.println("计算机名:" + address3.getHostName());
		System.out.println("IP地址:" + address3.getHostAddress());
		System.out.println();
		
		/*
		 * 获取其它地址
		 */
		InetAddress address4 = InetAddress.getByName("baidu.com");
		System.out.println("计算机名:" + address4.getHostName());
		System.out.println("IP地址:" + address4.getHostAddress());
		System.out.println();
	}
}

2、URL类

1)简介:

(1)URL(Uniform Resource Locator)统一资源定位符,表示Internet上某一资源的地址

(2)URL由两部分组成:协议名称和资源名称,中间用冒号隔开

(3)在java.net包中,提供了URL类来表示URL

2)使用URL读取网页内容

(1)通过URL对象的openStream()方法可以得到指定资源的输入流

(2)通过输入流可以读取、访问网络上的数据

3)URL类使用示例代码:

import java.net.MalformedURLException;
import java.net.URL;

/**
 * URL常用方法
 */
public class URLDemo {
	public static void main(String[] args) throws MalformedURLException {
		// 创建URL实例
		URL url = new URL("http://www.baidu.com");
		URL url2 = new URL(url, "/index.html?uname=1#test"); // 在原有的URL资源上再创建URL实例,#后面表示锚点
		System.out.println("协议" + url2.getProtocol());
		System.out.println("主机" + url2.getHost());
		// 如果未指定端口号,则使用默认的端口号,此时getPort()返回-1
		System.out.println("端口" + url2.getPort());
		System.out.println("文件路径" + url2.getPath());
		System.out.println("文件名称:" + url2.getFile());
		System.out.println("相对路径" + url2.getRef());
		System.out.println("查询字符串" + url2.getQuery());
	}
}

 

三、Socket实现TCP编程

1、Socket通信模型

 

1)上图的通信模型的顺序为:

(1)先建立服务端监听Soket,等待客户端请求。

(2)客户端创建socket,向服务端发送请求。

(3)服务端接收请求,并创建连接socket到此步骤时,服务端与客户端建立了连接。

(4)服务端和客户端开始通信(InputStream、OutputStream)。

(5)最后关闭socket与相关资源。

2、Socket实现TCP编程通信的实现步骤

1)服务端:

(1)创建ServerSocket对象,绑定监听端口

(2)通过accept()方法监听客户端的请求

(3)建立连接后,通过输入流读取客户端发送的请求信息

(4)通过输出流向客户端发送相应信息

(5)关闭相关资源

代码示例:

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 服务端
 * 基于TCP协议的Socket通信 -- 单线程
 */
public class TCPServer {
	
	public static void main(String[] args) {
		try {
			// 1.创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听
			ServerSocket serverSocket = new ServerSocket(8888);
			// 2.调用accept()方法开始监听,等待客户端的连接
			System.out.println("服务器即将启动,等待客户端的连接***");
			Socket socket = serverSocket.accept();
			// 3.获取输入流,并读取客户端信息
			InputStream is = socket.getInputStream();
			InputStreamReader irs = new InputStreamReader(is);
			BufferedReader br = new BufferedReader(irs);
			String info = null;
			while((info=br.readLine()) != null){
				System.out.println("服务器接收到消息:" + info);
			}
			socket.shutdownInput();//关闭输入流
			// 4.获取输出流,响应客户端请求
		    OutputStream os = socket.getOutputStream();
			PrintWriter pw = new PrintWriter(os);// 包装为打印流
			pw.write("终于等到你!");
			pw.flush();
			
			// 5.关闭资源
			pw.close();
			os.close();
			br.close();
			irs.close();
			is.close();
			socket.close();
			serverSocket.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

2)客户端:

(1)创建Socket对象,指明需要连接的服务器的地址和端口号

(2)连接建立后,通过输出流向服务器端发送请求信息

(3)通过输入流获取服务器相应的信息

(4)关闭相关资源

代码示例:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;

/**
 * 客户端
 * 基于TCP协议的Socket通信
 */
public class TCPClient {
	public static void main(String[] args) {
		try {
			// 1.创建客户端Socket,指定服务器地址和端口
			Socket socket = new Socket("localhost", 8888);
			
			// 2.获取输出流,向服务器端发送信息
			OutputStream os = socket.getOutputStream();//字节输出流
			PrintWriter pw = new PrintWriter(os);
			pw.write("客户端发信息来啦~~");
			pw.flush();
			socket.shutdownOutput();// 关闭输出流
			
			// 3.获取输入流,并读取服务器端的响应信息
			InputStream is =  socket.getInputStream();
			BufferedReader br = new BufferedReader(new InputStreamReader(is));
			String info = null;
			while((info=br.readLine()) != null){
				System.out.println("客户端接收到信息:" + info);
			}
			
			// 4.关闭资源
			br.close();
			is.close();
			pw.close();
			os.close();
			socket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

3、应用多线程来实现服务器与多客户端之间的通信的基本基本步骤

(1)服务器端创建ServerSocket,循环调用accept()等待客户端连接

(2)客户端创建一个socket并请求和服务器端连接

(3)服务器端接收客户端请求,创建socket与该客户建立专线连接

(4)建立连接的两个socket在一个单独的线程上对话

(5)服务器端继续等待新的连接

代码示例:

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

/**
 * 服务端
 * 基于TCP协议的Socket通信 -- 多线程实现多客户的通信
 */
public class TCPServerMulConnection {
	public static void main(String[] args) {
		try {
			// 创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听
			ServerSocket serverSocket = new ServerSocket(8888);
			// 调用accept()方法开始监听,等待客户端的连接
			System.out.println("服务器即将启动,等待客户端的连接***");
			Socket socket = null;
			int count = 0; // 记录客户端的连接
			// 循环监听等待客户端的连接
			while (true) {
				// 调用accept()方法开始监听,等待客户端的连接
				socket = serverSocket.accept();
				// 创建一个新的线程
				ServerThreadHelper serverThread = new ServerThreadHelper(socket);
				//serverThread.setPriority(4); //可设置线程优先级(优先级默认为5,数字越小,优先级越低;未设置优先级可能导致运行时速度非常慢,可适当降低)
				// 启动线程
				serverThread.start();
				count++; // 统计客户端的数量
				InetAddress address = socket.getInetAddress();
				System.out.println("第 " + count + " 个客户端连接成功!此客户端的ip为:" + address.getHostAddress());
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}


/**
 * 服务器端线程处理类
 */
class ServerThreadHelper extends Thread{
	// 和本线程相关的socket
	Socket socket = null;
	
	public ServerThreadHelper(Socket socket){
		this.socket = socket;
	}
	
	// 线程执行的操作,响应客户端请求
	public void run(){
		
		InputStream is = null;
		InputStreamReader irs = null;
		BufferedReader br = null;
		OutputStream os = null;
		PrintWriter pw = null;
		try {
			// 1.获取输入流,并读取客户端信息
			is = socket.getInputStream();
			irs = new InputStreamReader(is);
			br = new BufferedReader(irs);
			String info = null;
			while((info=br.readLine()) != null){
				System.out.println("服务器接收到消息:" + info);
			}
			socket.shutdownInput();//关闭输入流
			// 2.获取输出流,响应客户端请求
			os = socket.getOutputStream();
			pw = new PrintWriter(os);
			pw.write("终于等到你!");
			pw.flush();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			// 3.关闭资源
			try {
				if (pw!=null) {
					pw.close();
				}
				if (os!=null) {
					os.close();
				}
				if (br!=null) {
					br.close();
				}
				if (irs!=null) {
					irs.close();
				}
				if (is!=null) {
					is.close();
				}
				if (socket!=null) {
					socket.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
	}
}

 

四、Socket实现UDP编程

1、UDP编程简介

(1)UDP协议(用户数据报协议)是无连接、不可靠、无序的,特点是速度比较快

(2)进行数据传输时,首先要将要传输的数据定义成数据报(Datagram),在数据报中指明数据所要达到的Socket(主机地址和端口号),然后再将数据报发送出去

(3)相关的操作类:DatagramPacket:表示数据报包 DatagramSocket:进行端到端通信的类

2、Socket实现UDP编程

1)服务器端实现步骤

(1)创建DatagramSocket,指定端口号

(2)创建DatagramPacket,用于接收客户端请求

(3)接收客户端发送的数据信息

(4)读取数据

(5)关闭资源

示例代码:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

/**
 * 服务端
 * 基于UDP实现Socket通信
 */
public class UDPServer {

	public static void main(String[] args) throws IOException {
		/*
		 * 接收客户发送的数据
		 */
		// 1.创建服务器端DatagramSocket,指定端口
		DatagramSocket socket = new DatagramSocket(8800);
		// 2.创建数据报,用于接收客户端发送的数据
		byte[] data = new byte[1024];
		DatagramPacket packet = new DatagramPacket(data, data.length);
		// 3.接收客户端发送的数据
		System.out.println("服务器已启动,等待接收数据报中……");
		socket.receive(packet); // 此方法在接收到数据报之前会一直阻塞
		// 4.读取数据
		String info = new String(data, 0, packet.getLength());
		System.out.println("服务器接收到了新信息:" + info);
		
		/*
		 * 向客户端响应数据
		 */
		// 1.定义
		InetAddress address = packet.getAddress();
		int port = packet.getPort();
		byte[] data2 = "服务器已经收到信息啦~".getBytes();
		// 2.创建数据报,包含响应的数据信息
		DatagramPacket packet2 = new DatagramPacket(data2, data2.length, address, port);
		// 3.发送数据,返回給客户端
		socket.send(packet2);
		// 4.关闭资源
		socket.close();
	}

}

2)客户端实现步骤

(1)定义发送信息

(2)创建DatagramPacket,包含将要发送的信息

(3)创建DatagramSocket

(4)发送数据(通过DatagramSocket发送)

(5)关闭资源

示例代码:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * 客户端
 * 基于UDP实现Socket通信
 */
public class UDPClient {

	public static void main(String[] args) throws IOException {
		/*
		 * 发送消息给服务端
		 */
		// 1.定义服务器的地址、端口号、数据报
		InetAddress address = InetAddress.getByName("localhost");
		int port = 8800;
		byte[] data = "你好!我是客户端。".getBytes();
		// 2.创建数据报,包含发送的数据信息
		DatagramPacket packet = new DatagramPacket(data, data.length, address, port);
		// 3.创建DatagramSocket对象
		DatagramSocket socket = new DatagramSocket();
		// 4.向服务器端发送数据报
		socket.send(packet);
		
		/*
		 * 接收服务端响应
		 */
		// 1.创建数据报,用于接收服务器端响应的数据
		byte[] data2 = new byte[1024];
		DatagramPacket packet2 = new DatagramPacket(data2, data2.length);
		// 2.接收服务器响应的数据
		socket.receive(packet2);
		// 3.读取数据
		String reply = new String(data2, 0, packet2.getLength());
		System.out.println("客户端接收到新信息:" + reply);
		// 4.关闭资源
		
	}

}

 

五、Socket实现UDP编程

1、使用多线程编写网络程序时,可以将线程的优先级降低,线程的优先级默认是五,数字越小,优先级越低;未设置优先级可能导致运行时速度非常慢,可适当降低。

2、对于同一个socket,如果关闭了输出流,则与该输出流相关的socket也会被关闭,所以一般不用关闭流,直接关闭socet即可。

3、可以将一个对象序列化之后,通过流的方式在网络上传输

ObjectOutputStream oos = new ObjectOutputStream(os);

oos.writeObject(User);

4、网络上传输文件,也是将文件转换为流,通过流的方式在网络上传输

BufferedOutputStream  fos = new  BufferedOutputStream(new FileOutputStream(new File("d://")));

 

转载于:https://my.oschina.net/u/3696939/blog/1574166

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值