一、网络编程入门
(一)软件结构
- C/S结构 :全称为Client/Server结构,是指客户端和服务器结构。常见程序有QQ、迅雷等软件。
- B/S结构 :全称为Browser/Server结构,是指浏览器和服务器结构。常见浏览器有谷歌、火狐等。
(二)网络通信协议
网络通信协议:通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则。在计算机网络中,这些连接和通信的规则被称为网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换。
TCP/IP协议:传输控制协议/因特网互联协议( Transmission Control Protocol/Internet Protocol),是Internet最基本、最广泛的协议。它定义了计算机如何连入因特网,以及数据如何在它们之间传输的标准。它的内部包含一系列的用于处理数据通信的协议,并采用了4层的分层模型,每一层都呼叫它的下一层所提供的协议来完成自己的需求。
(三)协议分类
通信的协议还是相对复杂的,java.net 包中包含的类和接口,它们提供低层次的通信细节。开发者可以直接使用这些类和接口,来专注于网络程序开发,而不用考虑通信的细节。
java.net 包中提供了两种常见的网络协议的支持:
- TCP:传输控制协议 (Transmission Control Protocol)。TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。
- UDP:用户数据报协议(User Datagram Protocol)。UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。
(四)网络编程三要素
1.协议:计算机网络通信必须遵守的规则
2.IP地址:指互联网协议地址(Internet Protocol Address),俗称IP。
- IPv4:是一个32位的二进制数,通常被分为4个字节,表示成a.b.c.d 的形式,例如192.168.65.100 。其中a、b、c、d都是0~255之间的十进制整数,那么最多可以表示42亿个。
- IPv6:采用128位地址长度,每16个字节一组,分成8组十六进制数,表示成ABCD:EF01:2345:6789:ABCD:EF01:2345:6789,号称可以为全世界的每一粒沙子编上一个网址,这样就解决了网络地址资源数量不够的问题。
3.端口号:用两个字节表示的整数,它的取值范围是0-65535。其中,0-1023之间的端口号用于一些知名的网络服务和应用,普通的应用程序需要使用1024及以上的端口号。如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败。
二、TCP编程
(一)概述
TCP通信能实现两台计算机之间的数据交互,通信的两端,要严格区分为客户端(Client)与服务端(Server)。
两端通信时步骤:
- 服务端程序,需要事先启动,等待客户端的连接。
- 客户端主动连接服务器端,连接成功才能通信。服务端不可以主动连接客户端。
在Java中,提供了两个类用于实现TCP通信程序:
- 客户端:java.net.Socket 类表示。创建Socket对象,向服务端发出连接请求,服务端响应请求,两者建立连接开始通信。
- 服务端:java.net.ServerSocket 类表示。创建ServerSocket对象,相当于开启一个服务,并等待客户端的连接。
(二)Socket类
Socket 类:该类实现客户端套接字,套接字指的是两台设备之间通讯的端点。
1.构造方法
public Socket(String host, int port)
创建套接字对象并将其连接到指定主机上的指定端口号。如果指定的host是null ,则相当于指定地址为回送地址。
2.成员方法
public InputStream getInputStream() : 返回此套接字的输入流。
public OutputStream getOutputStream() : 返回此套接字的输出流。
public void close() :关闭此套接字。
public void shutdownOutput() : 禁用此套接字的输出流。
(三)ServerSocket类
ServerSocket类:这个类实现了服务器套接字,该对象等待通过网络的请求。
1.构造方法
public ServerSocket(int port) :使用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指定的端口号上,参数port就是端口号。
2.成员方法
public Socket accept() :侦听并接受连接,返回一个新的Socket对象,用于和客户端实现通信。该方法会一直阻塞直到建立连接。
(四)TCP编程
- 【服务端】启动,创建ServerSocket对象,等待连接。
- 【客户端】启动,创建Socket对象,请求连接。
- 【服务端】接收连接,调用accept方法,并返回一个Socket对象。
- 【客户端】Socket对象,获取OutputStream,向服务端写出数据。
- 【服务端】Scoket对象,获取InputStream,读取客户端发送的数据。
- 【服务端】Socket对象,获取OutputStream,向客户端回写数据。
- 【客户端】Scoket对象,获取InputStream,解析回写数据。
- 【客户端】释放资源,断开连接。
服务端代码:
package com.qf.tcp2;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class TCPServer_IM {
public static void main(String[] args){
System.out.println("服务端启动。。。");
Socket server = null;
InputStream is = null;
OutputStream os = null;
//1,创建SocketServer对象,绑定端口,等待连接
try {
ServerSocket serverSocket = new ServerSocket(8888);
Scanner sc =new Scanner(System.in);
//2,
server = serverSocket.accept();
while(true){
//3,通过Socket获取输入流
is = server.getInputStream();
//4,读取数据
byte[] buff = new byte[1024];
int len = is.read(buff);
String msg = new String(buff, 0, len);
System.out.println("客户端:"+msg);
//5,服务端回写数据
os = server.getOutputStream();
//System.out.println("请输入服务端信息:");
String serverMsg = sc.nextLine();
os.write(serverMsg.getBytes());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(os!=null){
os.close();
}
if(is!=null){
is.close();
}
if(server!=null){
server.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端代码:
package com.qf.tcp2;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class TCPClient_IM {
public static void main(String[] args) {
System.out.println("客户端启动。。。。");
Scanner sc = new Scanner(System.in);
Socket client = null;
OutputStream os = null;
InputStream is = null;
try {
//1,创建Socket对象,连接到指定的服务端
client = new Socket("localhost",8888);
while(true){
//2,通过socket对象获取输出流,给服务端发送消息
os = client.getOutputStream();
//System.out.println("请录入客户端的消息:");
String input = sc.nextLine();
os.write((input).getBytes());
//3,获取服务器发送的消息
is = client.getInputStream();
//4,读取数据
byte[] buff = new byte[1024];
int len = is.read(buff);
String msg = new String(buff, 0, len);
System.out.println("服务端:"+msg);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(is!=null){
is.close();
}
if(os!=null){
os.close();
}
if(client!=null){
client.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
三、UDP编程
(一)概述
UDP编程主要用到两个类DatagramPacket和DatagramSocket。
(二)DatagramSocket类
此类表示用来发送和接收数据报包的套接字。
构造方法:
- DatagramSocket(int port) ~创建数据报套接字并将其绑定到本地主机上的指定端口。
- DatagramSocket(int port, InetAddress laddr) ~创建数据报套接字,将其绑定到指定的本地地址。
(三)DatagramPacket类
此类表示数据报包,通信双方都要先构造好相应的数据包(java.net.DatagramPacket)。
- 在DatagramPacket包中的函数 int getLength()返回实际接受的字节数,
DatagramPacket packet = new DatagramPacket(data,data.length);
- 要想接受端给发送端回信息,就需要知道发送端的IP地址InetAddress getAddress()和发送端进程所绑定的端口号int getPort()。
DatagramPacket packet2 = new DatagramPacket(data2, data2.length, address, port);
(四)UDP编程
客户端1代码:
package com.qf.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Client1 {
public static void main(String[] args) throws IOException {
System.out.println("客户端1启动。。。。");
/**
* 接收信息
*/
//1,创建一个指定端口的DatagramSocket
DatagramSocket socket = new DatagramSocket(8888);
//2,创建一个字节数组
byte[] data = new byte[1024];
//3,创建DatagramPacket接收客户端的信息
DatagramPacket packet = new DatagramPacket(data,data.length);
//4,接收消息
socket.receive(packet);
//读取数据
String msg = new String(data, 0, packet.getLength());
System.out.println("客户端2:"+msg);
/**
* 发送消息
*/
//5,指定地址,端口
byte[] data2 = "你好,我是客户端1".getBytes();
InetAddress localhost = InetAddress.getByName("localhost");
int port = 9999;
//6,创建消息
DatagramPacket packet2 = new DatagramPacket(data2,data2.length,localhost,port);
//7,发送消息
socket.send(packet2);
//8,关闭套接字
socket.close();
}
}
客户端2代码:
package com.qf.udp;
import java.io.IOException;
import java.net.*;
public class Client2 {
public static void main(String[] args) throws IOException {
System.out.println("客户端2启动。。。。。");
/**
* 发送消息
*/
//1,创建DatagramSocket,指定端口
DatagramSocket socket = new DatagramSocket(9999);
//2,指定地址端口
InetAddress localhost = InetAddress.getByName("localhost");
int port = 8888;
//3,要发送的消息
byte[] data = "你好,客户端1".getBytes();
//4,创建
DatagramPacket packet = new DatagramPacket(data,data.length,localhost,port);
//5,发送
socket.send(packet);
/**
* 接收消息
*/
//5,创建一个数组
byte[] data2 = new byte[1024];
DatagramPacket packet2 = new DatagramPacket(data2,data2.length);
//6,接受消息
socket.receive(packet2);
//7,解析发送过来的消息
String msg = new String(data2, 0, packet2.getLength());
System.out.println("客户端1:"+msg);
//8,关闭套接字
socket.close();
}
}