Java 网络编程
网络通信协议
TCP/IP协议(Transmission Control Protocal/Internet Protoal 传输控制协议):包括TCP协议、IP协议、UDP协议(User Datagram Protocol)、ICMP协议(Internet Control Message Protocol)和其他一些协议的协议组。
层次结构:
TCP/IP协议分为4层结构,分别是应用层、传输层、网络层、链路层。每层分别负责不同的通信功能。
应用程:主要负责应用程序的协议,如HTTP协议FTP协议等。
传输程:主要使网络程序进行通信,在进行网络通信时,可以采用TCP协议,也能使用UDP协议。
网络层:网络层是整个TCP/IP协议的核心,它主要用于将传输的数据进行分组,将分组的数据发送到目标计算机或网络。
链路层:用于定义物理传输通道,它通常是对某些网络连接设备的驱动协议,例如针对光纤、双绞线提供的驱动。
IP地址和端口号
- IP地址:每台计算机都有一个标识号,通过这个标识号就可以指定接收数据的计算机或发送数据的计算机,在TCP/IP协议中,这个标识号就是IP地址,它可以唯一标识一台计算机,目前广泛使用的是IPv4,他是有4个字节大小的二进制数(32位的二进制数)表示。
- 端口号:IP地址可以连接到指定的计算机,但是如果要访问目标计算机的某个应用程序,就需要指定端口号。计算机中不同的应用程序是通过端口号区分。端口号是用两个字节(16位二进制数)表示的,取值范围为
0~65535
.其中0~1023
之间的端口号用于一些知名的网络服务和应用,普通用户需要使用1024以上的端口号,避免端口号被另一个应用或服务所占用。
InetAddress
在java中提供了一个InetAddress类
,用于封装一个IP地址,并提供了一系列与IP地址相关的方法。
public class MyInetAddress {
public static void main(String[] args) throws Exception {
InetAddress localHost = InetAddress.getLocalHost();
InetAddress baiduAddress = InetAddress.getByName("www.baidu.com");
System.out.println("我的ip地址是: " + localHost.getHostAddress());
System.out.println("百度的IP地址为: " + baiduAddress.getHostAddress());
System.out.println("2秒可否到达 " + baiduAddress.isReachable(2000));
System.out.println("百度的主机名 : " + baiduAddress.getHostName());
}
}
UDP和TCP协议
- UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接,也就是说,当计算机A给计算机B发送数据时,A不会确认B是否存在,就会发送数据,同样B在收到数据时,也不会向A反馈是否收到数据。由于在使用UDP协议消耗资源小,通信效率高,所有常用于音频、视频和普通数据的传输。比如视频会议都使用UDP协议,因为在这种情况下偶尔丢失一两个数据包,也不会对接收结果产生太大影响。
- TCP协议是面向连接的通信协议,即在传输数据前先在发送端和接收端建立逻辑连接,然后在传输数据,它提供了两台计算机之间可靠无差错的数据传输,在TCP连接中必须要明确客户端和服务端,有客户端发出连接请求,每次连接的创建都需要经过三次握手。
Java TCP通信
在java中提供了两个类用于实现TCP程序,一个是ServerSocket
类,用于表示服务器端,一个是Socket
类,用于表示客户端。通信时先创建代表服务器端的ServerSocket
对象,该对象相当于开启一个服务,并等待客户端连接,然后创建代表客户端的Socket
对象向服务器端发送连接请求,服务器端响应请求,两者建立连接开始通信。
ServerSocket类
构造方法:
ServerSocket()
创建ServerScoket
对象并没有绑定端口号,这样对象创建的服务器没有监听任何端口,不能直接使用,还需要继续调用bind(SocketAddress endpoint)
方法绑定指定的端口号,才能正常使用。Serversocket(int port)
创建ServerSocket
对象时直接绑定端口号。端口可以指定为0,此时系统会分配一个还没有被其他网络程序所使用的端口号。Serversocket(int port, int backlog)
在上面的构造方法上增加一个backlog
参数,该参数用于指定在服务器忙的时,可以与之保持连接请求的等待客户数量,如果没有指定默认为50。Serversocket(int port, int backlog, InetAddress bindAddr)
该方法时建立在第三个构造基础上,还指定了相关IP地址,这种情况适用于计算机上有多块网卡和多个IP的情况。
ServerSocket server = null;
// 第一种
server = new ServerSocket();
server.bind(new InetSocketAddress(8080));
// 第二种
server = new ServerSocket(8080);
// 第三种
server = new ServerSocket(8080, 80);
// 第四种
server = new ServerSocket(8080,78, InetAddress.getLocalHost());
常用方法:
Socket类
构造方法:
Socket()
:该方法在创建Socket对象
时,并没有指定IP和端口号,也就意味着只是创建了客户端对象,并没有去连接任何服务器,该对象还需要调用```connect(SocketAddress endpoint) ``方法,才能完成与指定服务器的连接诶,其中参数endpoint用于封装IP地址和端口号。Socket(String host, int port )
,该方法在创建Socket对象
时,会根据参数去连接指定地址和端口上运行的服务器程序,其中参数host接收的是一个字符串形式的IP地址。Socket(InetAddress address, int port)
与上一个方法类似,参数address
用于接收InetAddress类型对象
,该对象封装一个IP地址。
Socket clinet = null;
// 第一种
clinet = new Socket();
clinet.connect(new InetSocketAddress(8080))
// 第二种
clinet = new Socket("127.0.0.1", 8080);
// 第三种
clinet = new Socket(InetAddress.getLocalHost(), 8080);
常用方法:
服务器端和客户端通信图:
java实现简单的TCP网络程序:
/**
* 服务器端
*/
public class MyServerScoket {
public static void main(String[] args) {
//产生一个ServerSocket
ServerSocket server = null;
BufferedInputStream buffin = null;
boolean flag = true;
try {
// 开启服务器,8080端口
server = new ServerSocket(8080);
System.out.println("服务器已经打开!!!");
while(flag) {
//设置监听器,监听来自客户端的请求,accept接收来自客户端发送的信息
//IO阻塞,持续监听客户端,有内容才取出来,没有获取客户端发送的信息一直阻塞
Socket socket = server.accept();
// 获取到客户端的一些信息
System.out.println("上线通知:" + "IP:" +
socket.getInetAddress() + " 端口:" + socket.getPort());
// 处理客户端发送过来的信息
InputStream in = socket.getInputStream();
buffin = new BufferedInputStream(in);
int len = 0;
byte[] by = new byte[1024];
while((len = buffin.read(by)) != -1){
String s = new String(by, 0, len);
System.out.println(s);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
server.close();
buffin.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 客户端
*/
public class SocketClient {
public static void main(String[] args) {
Socket socket = null;
try {
// 客户端和服务器开启连接,如果没有抛出异常,证明连接成功,可以发消息了
socket = new Socket("127.0.0.1", 8080);
System.out.println("客户端程序上线!!!!");
// 往服务器发送信息,out.write(xxx) 这才表示使用TCP传输数据
OutputStream out = socket.getOutputStream();
out.write("这是测试数据!".getBytes());
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}