socket网络编程
一、网络编程概述
网络编程的目的
直接或间接地通过网络协议与其它计算机实现数据交换,进行通讯
网络编程中有两个主要的问题
①如何准确地定位网络上一台或多台主机;定位主机上的特定的应用
②找到主机后如何可靠高效地进行数据传输
二、网络通信要素概述
通信双方地址:
① IP
② 端口号
三、IP和端口号
IP 地址:InetAddress
本地回环地址(hostAddress):
127.0.0.1
主机名(hostName):
localhost
IP地址分类方式1:
IPV4 和 IPV6
IPV4:4个字节组成,4个0-255。大概42亿,30亿都在北美,亚洲4亿。2011年初已经用尽。以点分十进制表示,如192.168.0.1
IPV6:128位(16个字节),写成8个无符号整数,每个整数用四个十六进制位表示,数之间用冒号(:)分开,如3ffe:3201:1401:1280:c8ff:fe4d:db39:1984
IP地址分类方式2:
公网地址(万维网使用)和私有地址(局域网使用)
192.168.开头的就是私有址址,范围即为192.168.0.-192.168.255.255,专门为组织机构内部使用
Internet上的主机有两种方式表示地址:
域名(hostName):www.baiidu.com
IP 地址(hostAddress):183.232.231.172
域名解析:
域名容易记忆,当在连接网络时输入一个主机的域名后,域名服务器(DNS)负责将域名转化成IP地址,这样才能和主机建立连接
InetAddress类
方法声明 | 功能描述 |
---|---|
InetAddress getByName(String host) | 获取给定主机名的的IP地址,host参数表示指定主机 |
InetAddress getLocalHost() | 获取本地主机地址 |
String getHostName() | 获取本地IP地址的主机名 |
boolean isReachable(int timeout) | 判断在限定时间内指定的IP地址是否可以访问 |
String getHostAddress() | 获取字符串格式的原始IP地址 |
public class Test01 {
public static void main(String[] args) throws UnknownHostException {
// 获取给定主机名的的IP地址,host参数表示指定主机
InetAddress inetAddress = InetAddress.getByName("192.168.0.106");
// 获取获取本地IP地址的主机名
String hostName = inetAddress.getHostName();
// 获取IP地址
String address = inetAddress.getHostAddress();
System.out.println("hostName:" + hostName);
System.out.println("address:" + address);
}
}
四、网络协议
网络通信协议
计算机网络中实现通信必须有一些约定,即通信协议,对速率、传输代码、代码结构、传输控制步骤、出错控制等制定标准
通信协议分层的思想
在制定协议时,把复杂成份分解成一些简单的成份,再将它们复合起来。最常用的复合方式是层次方式,即同层间可以通信、上一层可以调用下一层,而与再下一层不发生关系
两个协议
① 传输控制协议TCP(Transmission Control Protocol)
② 用户数据报协议UDP(User Datagram Protocol)
TCP 和 UDP
TCP协议:
①使用TCP协议前,须先建立TCP连接,形成传输数据通道
②传输前,采用“三次握手”方式,点对点通信,是可靠的
③ TCP协议进行通信的两个应用进程:客户端、服务端
④在连接中可进行大数据量的传输
⑤传输完毕,需释放已建立的连接,效率低
UDP协议:
①将数据、源、目的封装成数据包,不需要建立连接
②每个数据报的大小限制在64K内
③发送不管对方是否准备好,接收方收到也不确认,故是不可靠的
④可以广播发送
⑤发送数据结束时无需释放资源,开销小,速度快
Socket
1、通信的两端都要有Socket,是两台机器间通信的端点
2、 网络通信其实就是Socket间的通信
3、Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输
4、一般主动发起通信的应用程序属客户端,等待通信请求的为服务端
Socket类的常用构造器
构造器 | 说明 |
---|---|
public Socket(InetAddress address,int port) | 创建一个流套接字并将其连接到指定 IP 地址的指定端口号 |
public Socket(String host,int port) | 创建一个流套接字并将其连接到指定主机上的指定端口号 |
Socket类的常用方法
方法 | 说明 |
---|---|
public InputStream getInputStream() | 返回此套接字的输入流 |
public OutputStream getOutputStream() | 返回此套接字的输出流 |
public InetAddress getInetAddress() | 此套接字连接到的远程 IP 地址;如果套接字是未连接的,则返回 null |
public InetAddress getLocalAddress() | 获取套接字绑定的本地地址 |
public int getPort() | 此套接字连接到的远程端口号 |
public int getLocalPort() | 返回此套接字绑定到的本地端口 |
public void close() | 关闭此套接字 |
public void shutdownInput() | 不能在从此套接字的输入流中接收任何数据 |
public void shutdownOutput() | 禁用此套接字的输出流 |
五、TCP网络编程
三次握手
1、TCP是面向连接的可靠协议、通过三次握手建立连接,通讯完成时拆除连接
2、tcp协议 需要先经历三次握手成功之后 在将数据发送给服务器端 确保服务器端是在 在将数据
TCP协议实现示意图
客户端发送数据四个步骤:
1、创建 Socket:根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务器的通信线路。若连接失败,会出现异常
2、打开连接到 Socket 的输入/出流: 使用 getInputStream()方法获得输入流,使用getOutputStream()方法获得输出流,进行数据传输
3、按照一定的协议对 Socket 进行读/写操作:通过输入流读取服务器放入线路的信息(但不能读取自己放入线路的信息),通过输出流将信息写入线程
4、关闭 Socket:断开客户端到服务器的连接,释放线路
package com.nnfx.test01;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
/**
* @author 杰仔正在努力
* @create 2022-12-17 21:26
*/
public class TcpClient {
public static void main(String[] args) throws IOException {
/**
* 1.创建发送端Socket对象(创建连接)
* 2.获取输出流对象;
* 3.发送数据;
* 4.释放资源;
*/
//1、创建发送端Socket对象(创建连接)
Socket socket = new Socket(InetAddress.getByName("nnfx.server.com"), 8090);
//2.获取输出流对象;
OutputStream outputStream = socket.getOutputStream();
//3.发送数据;
outputStream.write("nnfx".getBytes());
outputStream.close();
socket.close();
}
}
服务器端发送数据六个步骤:
1、创建接收端Socket对象
2、监听(阻塞:如果建立连接失败,程序会一直阻塞,不往下执行
3、获取输入流对象
4、获取数据
5、输出数据
6、释放资源
package com.nnfx.test01;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author 杰仔正在努力
* @create 2022-12-17 21:31
*/
public class TcpServer {
public static void main(String[] args) throws IOException {
/**
* 1.创建接收端Socket对象;
* 2.监听(阻塞:如果建立连接失败,程序会一直阻塞,不往下执行;
* 3.获取输入流对象;
* 4.获取数据;
* 5.输出数据;
* 6.释放资源;
*/
//1.创建接收端Socket对象;
ServerSocket serverSocket = new ServerSocket(8090);
//2.监听客户端发送数据给服务器 如果客户端一直没有发送数据给服务器 导致服务器端会在该方法一直阻塞
System.out.println("服务器正在等待客户端接收数据。。。。");
Socket socket = serverSocket.accept();
//3.获取输入流对象;
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = inputStream.read(bytes);
System.out.println("服务器端接收客户端发送的数据:" + new String(bytes,len));
inputStream.close();
socket.close();
serverSocket.close();
}
}
报错
Exception in thread "main" java.net.ConnectException: Connection refused: connect
at java.net.DualStackPlainSocketImpl.connect0(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:75)
at java.net.AbstractPlainSocketImpl
原因: ip 访问不同 防火墙 没有关闭 或者 只能够在局域网访问
六、UDP网络编程
UDP协议 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据报的方法,俗称面向无连接
核心特点:面向无连接、不可靠的协议 、安全系数很低 容易丢包 但是传输速度是非常快 不需要类似于tcp协议三次握手。 聊天工具
发送数据四个步骤:
1、创建发送端socket对象;
2、提供数据,并将数据封装到数据包中;
3、通过socket服务的发送功能,将数据包发出去;
4、释放资源;
在windows 操作系统中,C:\Windows\System32\drivers\etc\HOSTS 文件中 新增 127.0.0.1 nnfx.server.com
package com.nnfx.socket;
import java.io.IOException;
import java.net.*;
/**
* @author 杰仔正在努力
* @create 2022-12-17 18:29
*/
public class UdpClient {
public static void main(String[] args) throws IOException {
// 1.创建发送端socket对象;
DatagramSocket datagramSocket = new DatagramSocket();
// 2.提供数据,并将数据封装到数据包中;
/**
* 参数1:发送数据 类型byte数组
* 参数2:发送数据长度
* 参数3:发送到服务器端ip地址
* 参数4:发送服务器端 端口号码
*/
byte[] msg = "nnfx".getBytes();
//走dns解析获取ip地址
InetAddress inetAddress = InetAddress.getByName("nnfx.server.com");
int port = 8080;
DatagramPacket datagramPacket = new DatagramPacket(msg, msg.length, inetAddress, port);
// 3.通过socket服务的发送功能,将数据包发出去;
datagramSocket.send(datagramPacket);
System.out.println("发送数据成功。。。");
// 4.释放资源;
datagramSocket.close();
}
}
接收数据五个步骤:
1、创建接收端socket对象;
2、接收数据;
3、解析数据;
4、输出数据;
5、释放资源;
package com.nnfx.socket;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
/**
* @author 杰仔正在努力
* @create 2022-12-17 18:46
*/
public class UdpServer {
public static void main(String[] args) throws IOException {
/**
* 1.创建接收端socket对象;
* 2.接收数据;
* 3.解析数据;
* 4.输出数据;
* 5.释放资源;
*/
//1、创建接收端socket对象
//监听端口8080
int port = 8080;
DatagramSocket datagramSocket = new DatagramSocket(port);
//2、接收数据
byte[] bytes = new byte[1024];
//数据包的形式接收
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
//开始监听客户端发送给服务器端数据,如果没有监听到数据则一直阻塞等待
System.out.println("开始接受客户端发送的数据....");
datagramSocket.receive(datagramPacket);
System.out.println("接收到数据。。。");
byte[] data = datagramPacket.getData();
String msg = new String(data);
//4、输出客户端发送给服务器端的内容
System.out.println(msg);
datagramSocket.close();
}
}