网络编程
来看看网络协议,还记不记得大学老师课堂上讲的TCP
一. 概述
计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路(网线,光纤,WiFi) 连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机体系.
二. 网络编程三要素
- IP地址
每台计算机的唯一标识号
- 端口
端口号就是唯一标识设备中的应用程序的,用于区分应用程序
- 协议
通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则,这些规则被称为 网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数 据交换.常见的协议有UDP协议和TCP协议,最常见的是Http、Https.
IP地址
ipv4 ipv6
-
inetAddress类操作
-
相关方法
1.static InetAddress getByName(String host) 确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址
2.String getHostName() 获取此IP地址的主机名
3.String getHostAddress() 返回文本显示中的IP地址字符串
4.static getLocalHost() 获取本机的IP对象
端口
( 设备上应用程序的唯一标识)
用两个字节表示的整数,它的取值范围是0~65535.其中,0~1023之间的端口号用于一些知名的网络服务和应用,普通的应用程序需要使用1024以上的端口号.如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败.
需要记忆的端口号:
mysql:3306
tomcat:8080
QQ:4301
协议
- 协议
计算机网络中,连接和通信的规则被称为网络通信协议
- UDP协议
UDP协议面向无连接的通信协议,数据传输占用的资源少,效率高,不能保证数据的完整性,不安全, 数量一般比较小,大概就是1M.
- TCP协议
1.传输控制协议 (Transmission Control Protocol)
2.TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输.在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,连接的创建都需要经过“三次握手”.
3.三次握手:TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠
1)第一次握手,客户端向服务器端发出连接请求,等待服务器确认
2)第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求
3)第三次握手,客户端再次向服务器端发送确认信息,确认连接
4.完成三次握手,连接建立后,客户端和服务器就可以开始进行数据传输了.由于这种面向连接的特性,TCP协议 可以保证传输数据的安全,所以应用十分广泛.例如上传文件、下载文件、浏览网页等
总结:
TCP协议下要想正常的传输数据必须连接客户端和服务器端, 效率低, 但是数据比较安全, 数据量没有限制.
三. UDP协议发送与接收数据
UDP编程类型介绍
- UDP协议
- 构造方法
1.DatagramSocket(): //创建数据报套接字对象并将其绑定到本机地址上的任何可用端口【一般用于发送端】
2.DatagramSocket(int port)://创建数据报套接字并将其绑定指定的可用端口【一般用于接收端】
//创建数据包,发送长度为len的数据包到指定主机的指定端口
3.DatagramPacket(byte[] buf,int len,InetAddress add,int port):
- 常用方法
套接字的方法 :
void send(DatagramPacket p) 发送数据报包
void close() 关闭数据报套接字
void receive(DatagramPacket p) 从此套接字接受数据报包
数据报包的方法 :
byte[] getData() 返回数据缓冲区
int getLength() 返回要发送的数据的长度或接收的数据的长度
int getPort() 获取发送数据报包对象程序的端口号
聊天小程序
发送端:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class UDPSend {
public static void main(String[] args) throws Exception{
DatagramSocket soc = new DatagramSocket();
Scanner sc = new Scanner(System.in);
while (true){
System.out.print("请输入要发送的数据: ");
String rMsg = sc.nextLine();
DatagramPacket sdp = new DatagramPacket(rMsg.getBytes(),
rMsg.getBytes().length,
InetAddress.getLocalHost(),
8888);
soc.send(sdp);
//接收
DatagramPacket rdp = new DatagramPacket(new byte[1024],1024);
soc.receive(rdp);
System.out.println("收到:"+new String(rdp.getData(),0,rdp.getLength()));
}
}
}
接收端:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.Scanner;
public class UDPReceive {
public static void main(String[] args) throws Exception{
//创建套接字对象
DatagramSocket soc = new DatagramSocket(8888);
//创建键盘录入对象
Scanner sc= new Scanner(System.in);
while (true){
DatagramPacket rdp = new DatagramPacket(new byte[1024],1024);
soc.receive(rdp);
String rMsg = new String(rdp.getData(),0,rdp.getLength());
System.out.println("接收: "+rMsg);
//发送
System.out.print("发送:");
String s = sc.nextLine();
DatagramPacket sdp = new DatagramPacket(s.getBytes(),
s.getBytes().length,
rdp.getAddress(),
rdp.getPort());
soc.send(sdp);
}
}
}
UDP协议中广播与组播
- 广播
1.当前主机与网络中的所有主机通信.
2.广播地址必须为 255.255.255.255. 局域网下: 192.168.79.255
public class UDPBoradcast {
public static void main(String[] args) throws Exception {
DatagramSocket soc = new DatagramSocket();
String msg = "大家好,才是真的好!!!";
DatagramPacket dp = new DatagramPacket(
msg.getBytes(),
msg.getBytes().length, // InetAddress.getByName("255.255.255.255"),
InetAddress.getByName("192.168.79.255"), // 小型局域网
9999 );
soc.send(dp);
}
}
- 组播
1.组播是指把信息同时传递给一组目的地址.组播地址的范围是224.0.0.0 ~ 239.255.255.255,如果超 出这个范围可能就会抛出异常.
2.参与组播的所有主机的套接字必须是MulticastSocket类的对象,它是DatagramSocket的子类,因此组 播套接字也是UDP协议的一种.
辅助理解: 组播就类似于群聊,向一个群中发送消息,只有加入群的人才能收到消息.因此不调用joinGroup方 法,接受端无法收消息.
- 方法
1.MulticastSocket() //创建组播套接字
2.MulticastSocket(int port) //创建组播套接字并将其绑定到特定端口
- 常用方法
1.joinGroup(InetAddress mcastaddr) 加入组播
- 组播群编程
发送端
public static void main(String[] args) throws IOException {
// 创建组播发送端
MulticastSocket msoc = new MulticastSocket();
// 准备要发送的数据报包
DatagramPacket dp = new DatagramPacket(
"你好".getBytes(),
"你好".getBytes().length,
InetAddress.getByName("239.255.255.110"),
20000 );
msoc.send(dp);
}
}
接收端
public class MulticastReceive {
public static void main(String[] args) throws Exception {
// 创建组播接受端
MulticastSocket msoc = new MulticastSocket(20000);
// 接受端加入组播
msoc.joinGroup(InetAddress.getByName("239.255.255.110"));
// 准备接受数据的数据报包
DatagramPacket dp = new DatagramPacket(new byte[1024], 1024);
// 接受数据
msoc.receive(dp);
// 解析接收到数据
System.out.println(new String(dp.getData(), 0, dp.getLength()));
}
}
四. TCP编程
- TCP协议
1.传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传 输层通信协议.
2.必须经过三次握手建立连接通道.(客户端和服务端建立连接的时候就已经完成了)
3.双方就在这个通道交互数据.
4.要严格区分为客户端(Client)与服务端(Server)
5.Java为客户端提供了Socket类,为服务器端提供了ServerSocket类
- 套接字构造方法
1.Socket(InetAddress address,int port) //创建流套接字并将其连接到指定IP指定端口号
2.Socket(String host, int port) //创建流套接字并将其连接到指定主机上的指定端口号
3.ServerSocket(int port) //创建绑定到指定端口的服务器套接字
- 常用方法
1.InputStream getInputStream() //返回此套接字的输入流, Socket接受数据的方法
2.OutputStream getOutputStream() //返回此套接字的输出流 Soket发送数据用的方法
3.Socket accept() //监听要连接到此服务端的套接字并接受它
- 客户端与服务端收发数据步骤
1.[服务端]启动,创建ServerSocket对象,等待连接.
2.[客户端]启动,创建Socket对象,请求连接.
3.[服务端]接收连接,调用accept方法,并返回一个Socket对象.
4.[客户端]Socket对象,获取OutputStream,向服务端写出数据.
5.[服务端]Scoket对象,获取InputStream,读取客户端发送的数据.
TCP协议发送与接收
客户端:
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class TCPClient {
public static void main(String[] args) throws Exception{
Socket soc = new Socket("127.0.0.1",33333);
OutputStream os = soc.getOutputStream();
os.write("你好服务端!".getBytes());
//接收服务端响应
InputStream is = soc.getInputStream();
byte[] bs = new byte[1024];
int len = is.read(bs);
System.out.println("客户端接收:"+new String(bs,0,len));
soc.close();
}
}
服务端:
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServer {
public static void main(String[] args) throws Exception{
ServerSocket sc = new ServerSocket(33333);
Socket soc = sc.accept();
InputStream is = soc.getInputStream();
byte[] bs = new byte[1024];
int len = is.read(bs);
System.out.print("收到: "+new String(bs,0,len));
//回应
OutputStream os = soc.getOutputStream();
os.write("你好客户端1".getBytes());
}
}
多线程下文件的上传
客户端:
public class ThreadFileUploadClient extends Thread{
private String imageName;
public ThreadFileUploadClient(){}
public ThreadFileUploadClient(String imageName){
this.imageName = imageName;
}
@Override
public void run() {
FileInputStream fis = null;
Socket soc = null;
try {
soc = new Socket("127.0.0.1", 5678);
// 创建一个文件输入亏
fis = new FileInputStream("day24/a/"+imageName+".png");
// 获取向服务器上传的流
OutputStream os = soc.getOutputStream();
int i = 0;
while ((i = fis.read()) != -1) {
os.write(i);
}
soc.shutdownOutput();
// 停止上传的操作
// 读取服务端回写的消息
InputStream is = soc.getInputStream();
byte[] bs = new byte[1024];
int len = is.read(bs);
System.out.println(new String(bs, 0, len));
} catch (IOException e) {
e.printStackTrace();
}finally {
if(fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (soc != null){
try {
soc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public class TestThreadUploadClient {
public static void main(String[] args) {
new ThreadFileUploadClient("1").start();
new ThreadFileUploadClient("2").start();
new ThreadFileUploadClient("3").start();
}
}
服务端:
public class ThreadFileUploadServer {
public static void main(String[] args) throws IOException {
ServerSocket sc = new ServerSocket(5678);
while (true) {
// 监听用户的请求
Socket soc = sc.accept();
// 创建一个线程完成读取用户上传数据并把数据服务器本地的操作
new Thread() {
@Override
public void run() {
FileOutputStream fos = null;
try {
// 获取到Socket的输入流
InputStream is = soc.getInputStream();
// 创建文件输出流,把数据写到本地
fos = new FileOutputStream(
"day24/upload/" + UUID.randomUUID() + ".png");
int i = 0;
while ((i = is.read()) != -1) {
fos.write(i);
}
// 回写数据
OutputStream os = soc.getOutputStream();
os.write("success".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}.start();
}
}
}