Java基础之网络编程
网络编程
网络模型:OSI(开放系统互联)参考模型、TCP/IP参考模型。
网络通信的要素:
1.IP地址InetAddress:网络中设备的标识。不容易记忆,可以用主机名称。
本地回环地址是:127.0.0.1,主机名称:localhost。
2.端口号(逻辑端口):数据要发送到对方指定的应用程序上,为了标识这些应用程序就给这些网络应用程序都用数字进行标识,将这些数字标识就称为端口。用于标识进程的逻辑地址,不同进程的标识,有效端口号:0~65535,其中0~1024为系统使用或保留的端口。
3.传输协议(通信协议):国际组织定义了通用的协议就是TCP/IP 。
通讯的规则,常见协议有:TCP、UDP。每个传输协议建立端点的方式是不同的。
类 InetAddress:表示互联网协议(IP)地址。该类没有构造函数,不能new对象,
通过类名调用静态方法getLocalHost获得本类对象,示例:InetAddress i = InetAddress.getLocalHost() 。
String getHostAddress():返回 IP 地址字符串(以文本表现形式)。
String getHostName():获取此IP地址的主机名。
示例:String ip = i.getHostAddress(), String name = i.getHostName()。
static InetAddress getByName(String host):在给定主机名的情况下确定主机的IP地址。import java.net.*;
class IPDemo
{
public static void main(String[] args) throws Exception
{
InetAddress i = InetAddress.getLocalHost();
System.out.println(i.toString());
String ip = i.getHostAddress(); //获取IP地址
String name = i.getHostName(); //获取主机名
System.out.println(ip);
System.out.println(name);
InetAddress ia = InetAddress.getByName(name); //通过主机名获取IP地址
System.out.println(ia);
}
}
UDP和TCP
UDP特点:
1.面向无连接,将数据封装成数据包,不需要建立连接。
2.每个数据包的大小限制在64k以内。
3.因为是无连接,容易丢失数据(丢包),是不可靠协议。
4.不需要建立连接,速度快。
TCP特点:
1.需要建立连接,形成传输数据的通道。
2.在连接中进行大量数据传输。
3.通过三次握手完成连接,是可靠协议。
4.必须建立连接,效率会稍低。
Socket:就是为网络服务提供的一种机制。所说的网络编程也就是Socket编程。
通信的两端都有Socket,网络通信就是Socket间的通信。数据在两个Socket间通过IO传输。
UDP的Socket服务该如何建立呢:使用Socket服务重点记住的就是流程,把步骤记住了然后通过查文档来写代码就可以,
流程很主要。
UDP传输发送端基本思路:
1.通过DatagramSocket对象创建udpSocket服务。
2.通过DatagramPacket对象将数据封装成数据包。
3.通过Socket服务的发送功能(send方法)将数据包发送出去。
4.关闭此数据报套接字。
UDP传输所对应的对象:DatagramSocket与DatagramPacket 。
步骤:1.建立发送端,接收端。2.建立数据包。3.调用Socket的发送接收方法。4.关闭Socket。
类 DatagramSocket:用来发送和接收数据报包的套接字。数据报套接字是包投递服务的发送或接收点。
每个在数据报套接字上发送或接收的包都是单独编址和路由的。
receive(DatagramPacket p):从此套接字接收数据报包。send(DatagramPacket p):从此套接字发送数据报包。
类 DatagramPacket:此类表示数据报包。数据报包用来实现无连接包投递服务。每条报文仅根据该包中包含的信息从一台
机器路由到另一台机器。在很多构造函数中,带有IP地址和端口的通常都是构造发送数据包的。
InetAddress getAddress():返回某台机器的IP地址,此数据报将要发往该机器或者是从该机器接收到的。
byte[] getData():返回数据缓冲区。int getLength():返回将要发送或接收到的数据的长度。
int getPort():返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的。
发送端与接收端是两个独立的运行程序。在发送端,要在数据包对象中明确目的地IP及端口。在接收端,要指定监听的端口。 BindException: Address already in use: Cannot bind:绑定异常:端口已经被使用了。UDP传输接收端基本思路:
1.建立udpSocket服务。通常会监听一个端口:给这个网络应用程序定义数字标识,方便于明确哪些数据发送过来该应用程序可以处理。
2.定义一个数据包,用于存储接收到的字节数据。将接收到的数据封装成对象方便于对数据的操作。
3.通过Socket服务的receive方法将接收到的数据存入数据包中。
4.通过数据包对象的特有功能操作这些数据,打印在控制台上。
5.关闭资源。--代码示例:
import java.net.*;
/*
需求:定义一个应用程序,通过UDP的传输方式,将一段文字数据发送出去。定义UDP的发送端。
思路:
1.建立udpSocket服务。2.提供一段数据,并将数据封装到数据包中。3.通过Socket服务的发送功能将
数据包发送出去。4.关闭资源。
*/
class UdpSend
{
public static void main(String[] args) throws Exception
{
//1.通过DatagramSocket对象创建udpSocket服务。
DatagramSocket ds = new DatagramSocket(8888);
//2.通过DatagramPacket对象将数据封装成数据包。
byte[] buf = "zhe shi wo de socket".getBytes();
DatagramPacket dp =
new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),1500);
//3.通过Socket服务的发送功能(send方法)将数据包发送出去。
ds.send(dp);
//4.关闭此数据报套接字。
ds.close();
}
}
/*
需求:定义一个应用程序,通过UDP的传输方式,用于接收并处理数据。定义UDP的接收端。
思路:
1.建立udpSocket服务。通常会监听一个端口:给这个网络应用程序定义数字标识,方便于明确哪些
数据发送过来该应用程序可以处理。
2.定义一个数据包,用于存储接收到的字节数据。将接收到的数据封装成对象方便于对数据的操作。
3.通过Socket服务的receive方法将接收到的数据存入数据包中。
4.通过数据包对象的特有功能操作这些数据,打印在控制台上。
5.关闭资源。
*/
class UdpRece
{
public static void main(String[] args) throws Exception
{
//1.通过DatagramSocket对象创建udpSocket服务。建立端点。
DatagramSocket ds = new DatagramSocket(1500);
//2.定义数据包。用于存储数据。
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
//3.通过Socket服务的receive方法将接收到的数据存入数据包中。
ds.receive(dp); //阻塞式方法。
//4.通过数据包对象的特有功能操作这些数据,打印在控制台上。
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(),0,dp.getLength());
int port = dp.getPort();
System.out.println(data+"::"+ip+"::"+port);
//5.关闭此数据报套接字。
ds.close();
}
}
TCP传输:分为客户端和服务器端,客户端所对应的对象是Socket,服务器端所对应的对象是ServerSocket 。
基本流程:
1.建立客户端和服务器端。
2.建立连接后,通过Socket中的IO流进行数据的传输。
3.关闭Socket。同样的,客户端与服务器端也是两个独立的应用程序。
通过查阅socket对象发现在建立对象时,就可以去连接指定的主机。因为TCP是面向连接的,所以在建立Socket服务时就要
有服务器端存在,并且连接成功形成通道,在该通道中进行数据的传输。通道一建立就产生了Socket流,Socket流里既有
输出流也有输入流。
TCP客户端基本思路:
1.创建客户端的Socket服务,并指定要连接的主机和端口。示例:Socket s = new Socket("127.0.0.1",10003);
2.获取Socket流中的输出流用于发送数据。示例:OutputStream out = s.getOutputStream(); out.write("tcp chuan shu".getBytes())
3.关闭socket。示例:s.close();
import java.net.*;
import java.io.*;
class TcpClient
{
public static void main(String[] args) throws Exception
{
//1.创建客户端的Socket服务,并指定要连接的主机和端口。
Socket s = new Socket("127.0.0.1",10003);
//2.获取Socket流中的输出流用于发送数据。
OutputStream out = s.getOutputStream();
out.write("zhe shi wo de tcp socket".getBytes());
//3.关闭socket。
s.close();
}
}
class TcpServer
{
public static void main(String[] args) throws Exception
{
//1.建立服务器端的socket对象,并监听一个端口。
ServerSocket ss = new ServerSocket(10003);
//2.通过ServerSokcet的accept方法获取连接过来的客户端对象,如果没有连接就会等,所以这个方法是阻塞式的。
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"...connected");
//3.使用客户端对象的读取流来读取发过来的数据,并打印在控制台。
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
String data = new String(buf,0,len);
System.out.println(data);
//4.关闭客户端。
s.close();
}
}
客户端需要明确服务器端的ip地址以及端口,这样才可以去试着建立连接,如果连接失败会出现异常,如果连接成功,说明客户端与服务端建立了通道,那么通过IO流就可以进行数据的传输,而Socket对象已经提供了输入流和输出流对象,通过getInputStream,getOutputStream获取即可。与服务端通讯结束后,关闭Socket。
TCP服务器端基本思路:
1.建立服务器端的socket对象,并监听一个端口。示例:ServerSocket ss = new ServerSocket(10003);
2.通过ServerSokcet的accept方法获取连接过来的客户端对象,如果没有连接就会等,所以这个方法是阻塞式的。示例:Socket s = ss.accept();
3.使用客户端对象的读取流来读取发过来的数据,并打印在控制台。示例:InputStream in = s.getInputStream();
4.关闭客户端:s.close(); 服务端通常不用关闭,为可选操作。 代码示例:
import java.net.*;
import java.io.*;
class TcpClient2
{
public static void main(String[] args) throws Exception
{
Socket s = new Socket("127.0.0.1",10004);
OutputStream out = s.getOutputStream();
out.write("服务端,你好!".getBytes());
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
s.close();
}
}
class TcpServer2
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(10004);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"...connected");
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
//Thread.sleep(10000);
OutputStream out = s.getOutputStream();
out.write("收到,客户端,你好!".getBytes());
s.close();
ss.close();
}
}
服务端需要明确它要处理的数据是从哪个端口进入的,当有客户端访问时要明确是哪个客户端,可通过accept()获取已连接的客户端对象,并通过该对象与客户端通过IO流进行数据传输。当该客户端访问结束,关闭该客户端。
Tcp传输最容易出现的问题:客户端连接上服务端,两端都在等待,没有任何数据传输。使用shutdownInput,shutdownOutput方法解决。
shutdownOutput():禁用此套接字的输出流。该方法的作用是关闭客户端的输出流,相当于给流中加入一个结束标记-1。
shutdownInput():此套接字的输入流置于“流的末尾”。
练习:客户端给服务端发送一行文本数据,服务端将该数据转换成大写再反馈给客户端。并且客户端可以不断地变换数据,当客户端输入"over"时,转换结束。代码示例:
/*
客户端:
源:键盘录入,输入流。目的:网络输出流。是纯文本数据,可以使用字符流。为提高效率加入缓冲。
步骤:1.建立客户端的Socket服务,指定要连接的主机和端口。
2.获取键盘录入。3.通过Socket流中的输出流将数据发送给服务端。
4.通过Socket流中的输入流获取服务端返回的大写信息。5.结束,关闭资源。
*/
import java.net.*;
import java.io.*;
class TransClient
{
public static void main(String[] args) throws Exception
{
Socket s = new Socket("127.0.0.1",10005);
//定义读取键盘数据的流对象。获取键盘录入。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
//通过Socket流中的输出流将数据发送给服务端。
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
//BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//通过Socket流中的输入流获取服务端返回的大写信息。
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
for(String line=null; (line=bufr.readLine())!=null; )
{
if(line.equals("over"))
break;
out.println(line);
//bufOut.write(line);
//bufOut.newLine();
//bufOut.flush();
String str = bufIn.readLine();
System.out.println(str);
}
bufr.close();
s.close();
}
}
class TransServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(10005);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"...connected");
//通过Socket流中的输入流获取到客户端发送的信息。
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
//通过Socket流中的输出流给客户端反馈信息。将大写数据写入到socket输出流,并发送给客户端。
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
//BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
for(String line=null; (line=bufIn.readLine())!=null; )
{
System.out.println(line);
out.println(line.toUpperCase());
//bufOut.write(line.toUpperCase());
//bufOut.newLine();
//bufOut.flush();
}
s.close();
ss.close();
}
}
/*
该例子出现的问题。
现象:客户端和服务端都在莫名的等待。
为什么呢?
因为客户端和服务端都有阻塞式方法。这些方法么没有读到结束标记。那么就一直等
而导致两端,都在等待。
*/
客户端与服务端就是基于网络应用的程序,这样的程序有很多,例如浏览器就是标准的客户端。服务器就是主机上的应程序。
telnet是Windows里面的远程登录命令,可以登录到一台主机上,它是个客户端。
在DOS命令行里输入 telnet 192.168.1.212 11000 可以连接网络中的一台主机,可以对这台主机进行命令式的配置。 C:\Windows\System32\drivers\etc 127.0.0.1的路径。
域名解析:想要将主机名翻译成IP地址需要域名解析,DNS域名解析服务器。客户端访问服务器端的时候优先走本地主机,本地主机没有再走网络DNS服务器,如果有对应的IP地址的话DNS服务器会将该地址返回给客户端,客户端再用此IP地址直接访问服务器端。
类 URL 代表一个统一资源定位符,它是指向互联网“资源”的指针。URL 可选择指定一个“端口”,它是用于建立到远程主机 TCP 连接的端口号。如果未指定该端口号,则使用协议默认的端口。例如,http 协议的默认端口为 80。URL url = new URL("http://127.0.0.1:10010/myweb/demo.html"); 创建URL对象。
String getFile() :获取此 URL 的文件名。url.getFile()。
String getHost() :获取此 URL 的主机名(如果适用)。
String getPath() :获取此 URL 的路径部分。
int getPort() :获取此 URL 的端口号。
String getProtocol() :获取此 URL 的协议名称。
String getQuery() :获取此 URL 的查询部 。代码示例如下:
import java.io.*;
import java.net.*;
class URLDemo
{
public static void main(String[] args) throws MalformedURLException
{
//创建URL对象。
URL url = new URL("http://127.0.0.1:10010");
String pro = url.getProtocol(); //获取协议名称。
String host = url.getHost(); //获取主机名。
int port = url.getPort(); //获取端口号。
String path = url.getPath(); //获取资源路径。
String file = url.getFile(); //获取文件名。
String que = url.getQuery(); //获取查询部。
System.out.println(pro);
System.out.println(host);
System.out.println(port);
System.out.println(path);
System.out.println(file);
}
}
URLConnection openConnection() :返回一个 URLConnection 对象,它表示到 URL 所引用的远程对象的连接。 示例:URLConnection conn = url.openConnection():通过URL的openConnection方法拿到URLConnection对象,使用该对象中的方法。抽象类 URLConnection 是所有类的超类,它代表应用程序和 URL 之间的通信链接。通过在 URL 上调用 openConnection 方法创建连接对象:URLConnection conn = url.openConnection()。 InputStream getInputStream():返回从此打开的连接读取的输入流。
OutputStream getOutputStream():返回写入到此连接的输出流。URLConnection 里面封装了Socket对象。示例:InputStream in = conn.getInputStream(); OutputStream out = conn.getOutputStream(); 代码示例如下:
import java.net.*;
import java.io.*;
class URLConnectionDemo
{
public static void main(String[] args) throws Exception
{
URL url = new URL("http://127.0.0.1:8080/myweb/demo.html");
//获取URL的远程连接对象。
URLConnection conn = url.openConnection();
System.out.println(conn);
//读取从服务器端接收到的数据。
InputStream in = conn.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf,0,len));
}
}