Java网络编程总结


一、网络编程基础概念


首先理清一个概念:网络编程不等于网站编程,网络编程即使用套接字来达到进程间通信,现在一般称为TCP/IP编程。

计算机网络:

把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大,功能强的网络系统,从而使众多的计算机可以方便的互相传递信息,共享硬件,软件,数据信息等资源。

计算机网络的主要功能:

资源共享
信息传输与集中处理
均衡负荷与分布处理
综合信息服务(www / 综合业务数字网络 ISDN)
计算机网络三高问题: 高并发,高性能,高可用。

计算机网络分类:

局域网
城域网
广域网
互联网
等等…
(Local Area Network;LAN) 通常我们常见的“LAN”就是指局域网,这是我们最常见、应用最广的一种网络

1、网络通信协议及接口


网络通信协议:

计算机网络中实现通信必须有一些约定,即通信协议;包括对速率,传输代码,代码结构,传输控制步骤,出错控制等制定的标准。

网络通信接口:

为了使两个节点之间能进行对话,必须在他们之间建立通信工具(即接口),使彼此之间,能进行信息交换。接口包括两部分:

硬件装置:实现结点之间的信息传送
软件装置:规定双方进行通信的约定协议
三、通信协议分层思想
为什么要分层:

由于结点之间联系很复杂,在制定协议时,把复杂成份分解成一些简单的成份,再将它们复合起来。最常用的复合方式就是层次方式,及同层间可以通信,上一层可以调用下一层,而与再下一层不发生关系。各层互不影响,利于系统的开发和扩展。

通信协议的分层规定:

把用户应用程序作为最高层,把物理通信线路作为最底层,将其间的协议处理分为若干层,规定每层处理的任务,也规定每层的接口标准。


2、通信协议分层思想

为什么要分层:

由于结点之间联系很复杂,在制定协议时,把复杂成份分解成一些简单的成份,再将它们复合起来。最常用的复合方式就是层次方式,及同层间可以通信,上一层可以调用下一层,而与再下一层不发生关系。各层互不影响,利于系统的开发和扩展。

3、参考模型 

二、 网络编程基础

1、两类传输协议:TCP、UDP

            TCP是Tranfer Control Protocol的 简称,是一种面向连接的保证可靠传输的协议。

            通过TCP协议传输,得到的是一个顺序的无差错的数据流。

            发送方和接收方的成对的两个socket之间必须建 立连接,

            以便在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,

            另一个socket可以要求进行连接,一旦这两个socket连接起来,

            它们就可以进行双向数据传输,双方都可以进行发送 或接收操作。

 

            UDP是User Datagram Protocol的简称,是一种无连接的协议

            每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,

            因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。

2、InetAddress类 

说到IP地址,就要引入一个类:InetAddress
此类表示互联网协议 (IP) 地址。

InetAddress类无构造方法

常用方法摘要

byte[] getAddress()
返回此 InetAddress 对象的原始 IP 地址。
static InetAddress getByName(String host)
在给定主机名的情况下确定主机的 IP 地址。
String getHostAddress()
返回 IP 地址字符串(以文本表现形式)。
String getHostName()
获取此 IP 地址的主机名。
static InetAddress getLocalHost()
返回本地主机。
127.0.0.1:本机地址,主要用于测试。别名:Localhost
案例一

import java.net.InetAddress;
import java.net.UnknownHostException;

public class TestIP {
    public static void main(String[] args) throws UnknownHostException {
        //InetAdress类表示IP地址

        //获取本机IP
        InetAddress ip = InetAddress.getLocalHost();
        System.out.println(ip);
        //获得主机名
        System.out.println(ip.getHostName());
        //获得IP地址
        System.out.println(ip.getHostAddress());
    }
}

 案例二

import java.net.InetAddress;
import java.net.UnknownHostException;

public class TestIP2 {
    public static void main(String[] args) throws UnknownHostException {
        InetAddress inetAddress = InetAddress.getByName("www.baidu.com");
        // 获取此 IP 地址的主机名。
        System.out.println(inetAddress.getHostName());
        //返回 IP 地址字符串(以文本表现形式)。
        System.out.println(inetAddress.getHostAddress());
    }
}

结果 


3、端口

  • IP地址用来标识一台计算机,但是一台计算机上可能提供多种网络应用程序,如何来区分这些不同的程序呢?这就要用到端口。
  • 端口是虚拟的概念,并不是说在主机上真的有若干个端口。
  • 通过端口,可以在一个主机上运行多个网络应用程序。端口的表示是一个16位的二进制整数,2个字节,对应十进制的0~65535   

查看端口

  • 用命令提示符cmd查看所有端口:netstat -ano
  • 查看具体程序:使用任务管理器查看PID

InetSocketAddress类

说到端口,则要引入一个类:InetSocketAddress

此类实现 IP 套接字地址(IP 地址 + 端口号)。

构造方法摘要                   

InetSocketAddress(InetAddress addr, int port)
根据 IP 地址和端口号创建套接字地址。
InetSocketAddress(int port)
创建套接字地址,其中 IP 地址为通配符地址,端口号为指定值。
InetSocketAddress(String hostname, int port)
根据主机名和端口号创建套接字地址。
常用方法摘要
InetAddress getAddress()
获取 InetAddress。
String getHostName()
获取 hostname。
int getPort()
获取端口号。

案例           

import java.net.InetAddress;
import java.net.InetSocketAddress;

public class TestPort {
    public static void main(String[] args) {
        InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1",8082);
        System.out.println(inetSocketAddress.getHostName());
        //获得InetSocketAddress的端口
        System.out.println(inetSocketAddress.getPort());
        System.out.println(inetSocketAddress.getHostString());
        //返回一个InetAddress对象(IP对象)
        InetAddress address = inetSocketAddress.getAddress();
    }
}

4、URL  

URI=URL+URN

URI:Uniform Resource Identifier ,统一资源标志符。
URL:Uniform Resource Locator,统一资源定位符。
URN:Uniform Resource Name,统一资源命名。


URL类
    构造方法摘要             

URL(String spec)
根据 String 表示形式创建 URL 对象。
URL(String protocol, String host, int port, String file)
根据指定 protocol、host、port 号和 file 创建 URL 对象。
URL(String protocol, String host, String file)
根据指定的 protocol 名称、host 名称和 file 名称创建 URL。
     常用方法摘要                                  

String getAuthority()
获取此 URL 的授权部分。
int getDefaultPort()
获取与此 URL 关联协议的默认端口号。
String getFile()
获取此 URL 的文件名。
String getHost()
获取此 URL 的主机名(如果适用)。
String getPath()
获取此 URL 的路径部分。
int getPort()
获取此 URL 的端口号。
String getUserInfo()
获取此 URL 的 userInfo 部分。

案例

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

public class TestURL {
    public static void main(String[] args) throws MalformedURLException {

        URL url2 = new URL("https://www.bilibili.com/");
        
        //获取此的授权部分 URL 。
        System.out.println(url2.getAuthority());

        //获取此 URL的文件名。
        System.out.println(url2.getFile());

        //获取端口
        System.out.println(url2.getPort());

        //获取主机
        System.out.println(url2.getHost());

        //获得默认端口
        System.out.println(url2.getDefaultPort());

        //获得路径
        System.out.println(url2.getPath());

        //获取该 URL的userInfo部分。
        System.out.println(url2.getUserInfo());
    }
}

三.基于Socket的java网络编程

(一)Socket的定义

网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket。

Socket通常用来实现客户方和服务方的连接。Socket是TCP/IP协议的一个十分流行的编程界面,

一个Socket由一个IP地址和一个端口号唯一确定。

但是,Socket所支持的协议种类也不光TCP/IP一种,因此两者之间是没有必然联系的。

在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。


(二)Socket通讯的过程

Server端Listen(监听)某个端口是否有连接请求,Client端向Server 端发出Connect(连接)请求,

Server端向Client端发回Accept(接受)消息。一个连接就建立起来了。

Server端和Client 端都可以通过Send,Write(socket.getOutputStream/socket.getInputStream)等方法与对方通信。

对于一个功能齐全的Socket,都要包含以下基本结构,其工作过程包含以下四个基本的步骤:

1. 创建Socket;

2. 打开连接到Socket的输入/出流;

3. 按照一定的协议对Socket进行读/写操作;

4.关闭Socket.(在实际应用中,并未使用到显示的close,虽然很多文章都推荐如此,不过在我的程序中,可能因为程序本身比较简单,要求不高,所以并未造成什么影响。)


(三)创建Socket

创建Socket在java包java.net中提供了两个类Socket和ServerSocket,

分别用来表示双向连接的客户端和服务端。这是两个封装得非常好的类,使用很方便。其构造方法如下:

客户端类的构造器:

       Socket(InetAddress address, int port);

  Socket(InetAddress address, int port, boolean stream);

  Socket(String host, int prot); //主要使用

  Socket(String host, int prot, boolean stream);

  Socket(SocketImpl impl)

  Socket(String host, int port, InetAddress localAddr, int localPort)

  Socket(InetAddress address, int port, InetAddress localAddr, int localPort)
服务端类的构造器:

       ServerSocket(int port);  //主要使用

  ServerSocket(int port, int backlog);

  ServerSocket(int port, int backlog, InetAddress bindAddr)

 

其中address、host和port分别是双向连接中另一方的IP地址、主机名和端 口号,stream指明socket是流socket还是数据报socket,localPort表示本地主机的端口号,localAddr和 bindAddr是本地机器的地址(ServerSocket的主机地址),impl是socket的父类,既可以用来创建serverSocket又可 以用来创建Socket。count则表示服务端所能支持的最大连接数。例如:

Socket client = new Socket("127.0.01", 5555);  //127.0.01任何时候都代表本机IP地址,5555是自定义的端口号

  ServerSocket server = new ServerSocket(5555);

  注意,在选择端口时,必须小心。每一个端口提供一种特定的服务,

只有给出正确的端口,才 能获得相应的服务。

0~1023的端口号为系统所保留,例如http服务的端口号为80,telnet服务的端口号为21,ftp服务的端口号为23, 

所以我们在选择端口号时,最好选择一个大于1023的数以防止发生冲突。

  在创建socket时如果发生错误,将产生IOException,在程序中必须对之作出处理。所以在创建Socket或ServerSocket是必须捕获或抛出例外。

(四)简单的Client/Server程序

程序实现的功能:

(1)服务器在每一台客户端登陆的时候:发送一条短信给客户端“服务器正在向你发送消息!”,然后在服务器端显示连接上的客户端主机地址。

(2)客户端连接上了,会接收到一条短信,并且可以对服务器一直进行发送短信。

(3)服务器可以一直接收客户端的短信。

(4)这里服务器只写一句话,但是想要像客户端那样一直写也是可以的,改一下就可以了。
1. 服务器端程序的编写

package com.xykj.server;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
    服务器端继承Thread
 * 可以实现简单的交互
 * */
public class Server extends Thread {

	// 定义服务器接口ServerSocket
	ServerSocket server = null;

	// 定义一个服务器,定义端口
	public Server(int port) {
		try {
			server = new ServerSocket(port);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	// 发送消息的线程
	@Override
	public void run() {
		super.run();
		try {
			System.out.println("服务器在启动中...等待用户的连接");
			//一直接收用户的连接,连接之后发送一条短信给用户
			while(true){
				// 建立socket接口,accept方法是一个阻塞进程,等到有用户连接才往下走
				// 定义Socket类
				Socket  socket = server.accept();
				//通过socket对象可以获得输出流,用来写数据
				OutputStream os = socket.getOutputStream();
				// 向客户端发送消息
				os.write("服务器正在向你发送消息!".getBytes());
				//在服务器上显示连接的上的电脑、
				System.out.println(socket.getInetAddress().getHostAddress()+"连接上了!");
				//通过socket对象可以获得输入流,用来读取用户数据
				InputStream is=socket.getInputStream();
				//读取数据
				int len=0;
				byte[] buf=new byte[1024];
				while ((len=is.read(buf))!=-1) {
					//直接把获得的数据打印出来
					System.out.println("服务器接收到客户端的数据:"+new String(buf,0,len));
				}
				
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

服务器的启动:

package com.xykj.server;


public class ServerTest {

	public static void main(String[] args) {
		
		//这里服务器只需要定义一个端口号就可以了,程序会自动获取IP地址
		//但是客户端需要连接这个服务器时,需要知道它的IP地址还有端口号
		//ip地址的查看方法:进入cmd窗口,输入ipconfig/all可以看到
		 Server server=new Server(6768);
		 server.start();
	}

}

2. 客户端程序的编写

package com.xykj.client;

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

public class Client extends Thread {
	
	//定义一个Socket对象
	Socket socket = null;

	public Client(String host, int port) {
		try {
			//需要服务器的IP地址和端口号,才能获得正确的Socket对象
			socket = new Socket(host, port);
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}

	@Override
	public void run() {
		//客户端一连接就可以写数据个服务器了
		new sendMessThread().start();
		super.run();
		try {
			// 读Sock里面的数据
			InputStream s = socket.getInputStream();
			byte[] buf = new byte[1024];
			int len = 0;
			while ((len = s.read(buf)) != -1) {
				System.out.println(new String(buf, 0, len));
			}
		
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	//往Socket里面写数据,需要新开一个线程
	class sendMessThread extends Thread{
		@Override
		public void run() {
			super.run();
			//写操作
			Scanner scanner=null;
			OutputStream os= null;
			try {
				scanner=new Scanner(System.in);
				os= socket.getOutputStream();
				String in="";
				do {
					in=scanner.next();
					os.write(("客户端:"+in).getBytes());
					os.flush();
				} while (!in.equals("bye"));
			} catch (IOException e) {
				e.printStackTrace();
			} 
			scanner.close();
			try {
				os.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

启动客户端:

package com.xykj.client2;
public class ClientTest2 {
	public static void main(String[] args) {
		//需要服务器的正确的IP地址和端口号
		 Client2 client2=new Client2("192.168.18.128", 6768);
		 client2.start();
	}
}

程序中要先开启服务端,在开启客户端,否则会报错!

还有就是一般的电脑是动态的IP地址,每天都在变化。要注意修改!

(五)支持多客户的client/server程序

在实际应用 中,往往是在服务器上运行一个永久的程序,它可以接收来自其他多个客户端的请求,

提供相应的服务。服务器总是在指定的端口上监听是否有客户请求,一旦监听到客户请求,

服务器就会启动一个专门的服务线程来响 应该客户的请求,

而服务器本身在启动完线程之后马上又进入监听状态,等待下一个客户的到来。

并且每一个用户对应一个固定的线程来接收信息。

服务器还会把接收到的信息发送给所有连接上的客户端。

示例:多人聊天室的实现:

1.服务器端的设计

package com.xykj.server2;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

/**
 * 可以实现和客户端的相互发送消息的交互 可以是多台电脑
 * */

public class Server2 extends Thread {
	// 用来存放连接上的用户的socket对象的值
	List list = new ArrayList<>();

	// 定义服务器接口ServerSocket
	ServerSocket server = null;

	// 定义一个服务器,定义端口
	public Server2(int port) {
		try {
			server = new ServerSocket(port);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	// 发送消息的线程
	@Override
	public void run() {
		super.run();
		try {

			while (true) {
				// 建立socket接口,accept方法是一个阻塞进程,等到有用户连接才往下走
				// 定义Socket类
				Socket socket = server.accept();
				// 在服务器显示连接的上的电脑、
				String message = socket.getInetAddress().getHostAddress().toString();
				System.out.println(message+"连接上了");
				// 向用户发送消息
				SendMessageToAllUser(message);
				// 把连接上的用户添加到集合;里面去
				list.add(socket);
				//开始新连接用户的线程,用于该可以一直读取数据
				new readerThread(socket).start();;
			}

		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	// 把消息发送给每一个用户,涉及到写的操作OutStream
	private void SendMessageToAllUser(String message) {
		// 拿到每一个用户的socket对象,对其进行写入数据
		for (Socket socket : list) {
			// 判读之前保存的连接是否还在
			if (socket != null && socket.isConnected()) {
				try {
					OutputStream os = socket.getOutputStream();
					os.write(message.getBytes());
					os.flush();// 刷新一下写入的数据,很有必要
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	// 读取客户端的信息
	class readerThread extends Thread {
		InputStream is = null;

		// 这里传入一个socket对象,因为每一个用户都要用一个不同的线程存放的socket对象来进行一直读取数据
		public readerThread(Socket socket) {
			try {
				// 获取输入流
				is = socket.getInputStream();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		@Override
		public void run() {
			super.run();
			try {
				int len = 0;
				byte[] buf = new byte[1024];
				while ((len = is.read(buf)) != -1) {
					// 把读取到的数据发送给其他用户
					SendMessageToAllUser(new String(buf, 0, len));
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

启动服务端:

package com.xykj.server;
public class ServerTest {
public static void main(String[] args) {
//这里服务器只需要定义一个端口号就可以了,IP地址程序会自动获取
//但是客户端需要连接这个服务器时,需要知道它的IP地址还有端口号
//ip地址的查看方法:进入cmd窗口,输入ipconfig/all可以看到
 Server2 server=new Server2(6768);
 server.start();
}
 
}

2.客户端的设计

 

这个和上个例子的客户端的设计基本一样,就不再重复粘贴了。

 

总结:上面主要是对java网络编程Socket接口类的使用,

还有TCP协议的应用(Socket的主要应用),

当然TCP还有一个比较主要的应用就是文件传输,

其中涉及到比较复杂的字符串处理(接收前和接收后都要),

有兴趣的可以自己设计一下。
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值