-
网络编程(套接字)
目录
通过java程序实现网络之间的数据传输,底层基于网络来传输的流。
-
网络模型
IP地址:确定在网络中的位置,IPv4 由4位0-255之间的数组成
端口:计算机和外部进行数据交互的媒介-----端口号(0-65535) 0-1024这些端口号大部分已经被系统占用,自己使用端口号的时候就从1025往后找
www.baidu.com----域名 通过DNS可以映射到对应的IP
-
SocketAddress(代表IP地址的类)
Constructor and Description |
---|
InetSocketAddress(InetAddress addr, int port) 从IP地址和端口号创建一个套接字地址。 |
InetSocketAddress(int port) 一个套接字地址,IP地址掩码地址和端口号指定的价值创造。 |
InetSocketAddress(String hostname, int port) 根据主机名和端口号创建一个套接字地址。 |
Modifier and Type | Method and Description |
---|---|
static InetSocketAddress | createUnresolved(String host, int port) 根据主机名和端口号创建一个悬而未决的套接字地址。 |
boolean | equals(Object obj) 将此对象与指定的对象进行比较。 |
InetAddress | getAddress() 得到 |
String | getHostName() 得到 |
String | getHostString() 返回主机名或地址的字符串形式,如果它没有一个主机名(这是用文字创造的)。 |
int | getPort() 获取端口号。 |
int | hashCode() 返回该套接字地址的hash码。 |
boolean | isUnresolved() 检查地址是否已被解决或不。 |
String | toString() 构造此InetSocketAddress的字符串表示形式。 |
public class InetSocketAddressDemo {
public static void main(String[] args) {
//创建表示IP和端口的对象
//127.0.0.1这个IP值一直指向本地,localhost和127.0.0.1互相映射
InetSocketAddress isa= new InetSocketAddress("localhost",8090);
//获取IP地址
System.out.println(isa.getAddress());
//获取主机名
System.out.println(isa.getHostName());
//获取端口号
System.out.println(isa.getPort());
}
}
-
UDP
底层基于流,不会建立链接,不可靠,传输速度快,适用场景:视频聊天等。
底层通过数据包来进行数据的传输,数据包大小一般不能超过64KB
Class DatagramSocket、Class DatagramPacket
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.util.Scanner;
/*
* #发送端
* */
public class UDPSender {
public static void main(String[] args) throws IOException {
//发送端,创建出网络编程对象-----指定要发送端的端口
DatagramSocket ds = new DatagramSocket(8009);
Scanner sc = new Scanner(System.in);
String s= sc.nextLine();
//创建数据包
//第一个参数要传输的字节数组
//第二个参数真正要发送的数据长度
//第三个参数知名要传输的IP地址和端口号
DatagramPacket dp = new DatagramPacket(s.getBytes(),s.getBytes().length,new InetSocketAddress("127.0.0.1",8080));
//发送数据包
ds.send(dp);
//关流----关闭底层字节流
ds.close();
}
}
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
/*
* #接收端
* */
public class UDPReceiverDemo {
public static void main(String[] args) throws IOException {
//创建套接字对象
DatagramSocket ds= new DatagramSocket(8080);
//创建数据包用于接收数据----第二个参数代表实际接收数据长度
DatagramPacket dp = new DatagramPacket(new byte[1024],1024);
//接收数据,把接收到的数据放到数据包中
ds.receive(dp);
//关流
ds.close();
//解析数据包
//dp.getData---获取数据---字节数组
//dp.getLength()----获取数据长度
System.out.println(new String(dp.getData(),0,dp.getLength()));
//获取ip地址
System.out.println(dp.getAddress());
//获取端口号
System.out.println(dp.getPort());
}
}
发送端:
1、创建套接字对象
2、创建需要发送端数据包(指定要发送的数据长度以及IP地址和端口号)
3、发送数据包
4、关流
接收端:
1、创建套接字对象(绑定具体的端口号)
2、创建需要接收的数据包(指定真实接收数据长度)
3、接收数据包
4、关流
5、解析数据包
案例:通过UDP协议实现简易的聊天室(通过线程来实现)
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.util.Scanner;
public class ChatDemo1 {
public static void main(String[] args) {
//开启线程
new Thread(new Sender()).start();
new Thread(new Receiver()).start();
}
}
class Sender implements Runnable{
//申明对象
DatagramSocket ds;
Scanner sc;
@Override
public void run() {
//对象初始化
try {
ds=new DatagramSocket();
sc=new Scanner(System.in);
while (true){
//录入数据
byte[] bs =sc.nextLine().getBytes();
//创建发送的数据包
DatagramPacket dp = new DatagramPacket(bs,bs.length,new InetSocketAddress("127.0.0.1",8090));
//发送
ds.send(dp);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Receiver implements Runnable{
DatagramSocket ds;
DatagramPacket dp;
@Override
public void run() {
//对象初始化
try {
ds=new DatagramSocket(8090);
dp=new DatagramPacket(new byte[1024],1024);
} catch (SocketException e) {
e.printStackTrace();
}
while (true){
//接收数据包
try {
ds.receive(dp);
//解析数据包
System.out.println(new String(dp.getData(),0,dp.getLength()));
System.out.println(dp.getAddress());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
-
TCP
底层基于流,建立链接(三次握手),可靠,传输速度慢,TCP通过字节流直接传输数据不需要数据包,就没有传呼数据的限制,适用场景:传输文件、下载电影等。
Socket、ServerSocket
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
/*
* #客户端
* */
public class TCPClientDemo {
public static void main(String[] args) throws IOException {
//创建套接字对象
Socket s = new Socket();
//发起链接---指定链接的IP和端口
//connect会发生阻塞
s.connect(new InetSocketAddress("127.0.0.1",8010));
//获取自带的字节输出流,写出的数据默认往服务器端写
OutputStream os =s.getOutputStream();
//通过自带数据输出流来写数据
//也有阻塞
os.write("服务器你好。。。".getBytes());
//通知服务器端数据已写完
s.shutdownOutput();
//获取自带的字节输入流
InputStream is =s.getInputStream();
byte[] bs = new byte[1024];
int len = -1;
while ((len=is.read(bs))!=-1){
System.out.println(new String(bs,0,len));
}
s.shutdownInput();
//关流
os.close();
}
}
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/*
* #服务器端
* */
public class TCPServerDemo {
public static void main(String[] args) throws IOException {
//创建TCP服务器端对象----绑定端口
ServerSocket ss= new ServerSocket(8010);
//接收链接-----返回一个Socket对象
//阻塞
Socket s=ss.accept();
//读取传过来的数据
InputStream is =s.getInputStream();
//通过自带的输入流来获取
//自建缓冲区
byte[] bs = new byte[1024];
int len = -1;
while ((len=is.read(bs))!=-1){//读取有阻塞
System.out.println(new String(bs,0,len));
}
//通知客户端数据已读完
s.shutdownInput();
//关流
//获取自带的字节输出流
OutputStream os=s.getOutputStream();
//往客户端写出数据
os.write("你好我也好。。。。".getBytes());
//通知客户端已经写完
s.shutdownOutput();
is.close();
}
}
客户端:
1、创建TCP客户端对象
2、发起链接(指明要发送的IP和端口)
3、获取自带的字节输出流
4、根据自带的字节流往服务器端写出数据
5、通知服务端已经写完数据
6、关流
服务器端:
1、创建TCP服务端对象,绑定端口
2、获取链接
3、获取自带的字节输入流对象
4、根据自带的字节输入流进行数据读取
5、通知客户端读取完成
6、关流
receive、connect、accept、write、read都会阻塞
通过TCP来实现文件复制
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
/*
* TCP复制文件#客户端
* */
public class FileCopyClient {
public static void main(String[] args) throws IOException {
//创建TCP客户端对象
Socket s = new Socket();
//发起链接
s.connect(new InetSocketAddress("127.0.0.1",9009));
//把外部文件读取进来
FileInputStream fis = new FileInputStream("D:\\1.txt");
//获取自带输出流
OutputStream os =s.getOutputStream();
//读取
byte[] bs = new byte[1024*1024*10];
int len=-1;
while((len=fis.read(bs))!=-1){
//往服务器端写数据
os.write(bs,0,len);
}
//通知服务器端已写完
s.shutdownOutput();
//关流
os.close();
fis.close();
}
}
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/*
* TCP复制文件#服务器
* */
public class FileCopyServer {
public static void main(String[] args) throws IOException {
//获取TCP服务器端对象绑定端口
ServerSocket ss = new ServerSocket(9009);
Socket s =ss.accept();
//获取自带字节输入流--读取客户端发来的
InputStream in =s.getInputStream();
//创建文件字节输出流
FileOutputStream fos = new FileOutputStream(new File("D:\\TCP1.txt"));
byte[] bs = new byte[1024*1024*10];
int len=-1;
while((len=in.read(bs))!=-1){
//往D盘写
fos.write(bs,0,len);
}
//通知客户端已经读取完毕
s.shutdownInput();
fos.close();
}
}