网络编程(套接字)
先解释一下套接字:Socket
所谓套接字,实际上是一个通信端点,每个套接字都有一个套接字序号,包括主机的IP地址与一个16位的主机端口号,即形如(主机IP地址:端口号)。例如,如果IP地址是210.37.145.1,而端口号是23,那么得到套接字就是(210.37.145.1:23)。总之,套接字Socket=(IP地址:端口号),套接字的表示方法是点分十进制的IP地址后面写上端口号,中间用冒号或逗号隔开。每一个传输层连接唯一地被通信两端的两个端点(即两个套接字)所确定。套接字可以看成是两个网络应用程序进行通信时,各自通信连接中的一个端点。通信时,其中的一个网络应用程序将要传输的一段信息写入它所在主机的Socket中,该Socket通过网络接口卡的传输介质将这段信息发送给另一台主机的Socket中,使这段信息能传送到其他程序中。因此,两个应用程序之间的数据传输要通过套接字来完成…
1.概念:
基于网络进行数据传输(IO流)
物理层,数据链路层,网络层,传输层(UDP,TCP),会话层,表示层,应用层
IP地址:主机在网络中的位置
IPv4是由0~255的数字组成16.30
域名解析器:把域名解析成对应的IP
端口:让计算机和外界进行数据交互的媒介 端口号(0-65535)从0~1024端口号基本都被系统占用了,使用时从后面开始使用
2.InetSocketAddress类—可以代表IP地址和端口号
package cn.tedu.net.address;
import java.net.InetSocketAddress;
public class InetSocketAddressDemo {
public static void main(String[] args) {
//创建代表IP地址和端口号的对象
//localhost解析成127.0.0.1永远指向本地
InetSocketAddress is=new InetSocketAddress("localhost",8080);
//获取信息
//获取IP地址
System.out.println(is.getAddress());
//获取主机名
System.out.println(is.getHostName());
}
}
3.UDP协议
底层基于流,传输不建立连接,不安全(不可靠)但是速度快
底层根据数据包(64KB)来进行传输
适用场景:直播、视频、音频等等
DatagramSocket、DatagranPacket
发送端:
1.创建UDP发送端对象
2.创建数据包(指定IP地址和端口以及要发送的数据)
3.发送数据包
4.关流
package cn.tedu.net.upd;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
public class UDPSenderDemo {
public static void main(String[] args) throws IOException {
//创建UDP发送端的对象
DatagramSocket ds=new DatagramSocket();
//创建数据包对象---准备发送数据
//第一个参数代表发送的数据
//第二个参数代表实际发送数据内容长度
//第三个参数代表IP地址和端口号
DatagramPacket dp=new DatagramPacket("早上好".getBytes(),"早上好".getBytes().length,
new InetSocketAddress("127.0.0.1",8081));
//发送数据包
ds.send(dp);
//关流
ds.close();
}
}
接收端:
1.创建UDP接收端对象,监听端口号
2.创建数据包(接收发送端发送数据)
3.接收数据包
4.关流
5.解析数据包
package cn.tedu.net.upd;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UDPReceiverDemo {
public static void main(String[] args) throws SocketException {
//创建UDP接收端的对象---监听发送端的端口号
DatagramSocket ds=new DatagramSocket(8081);
//创建数据包对象--接收数据
//第一个参数代表来接收数据的字节数组
//第二个参数代表真实的接收数据内容长度
DatagramPacket dp=new DatagramPacket(new byte[1024],1024);
//接收发送端发送的数据
ds.receive(dp);//会让线程产生阻塞状态
//关流
ds.close();
//解析数据包
//返回IP地址
System.out.println(dp.getAddress());
//getData()---接收到的数据
//getLength()---接收数据内容长度
//展示接收的数据
System.out.println(new String(dp.getData(),0,dp.getLength()));
}
}
练习:
通过UDP即实现简易聊天室(线程实现)
package cn.tedu.net.upd;
import com.sun.xml.internal.ws.resources.SenderMessages;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.util.Scanner;
public class UDPChatDemo {
public static void main(String[] args) {
//创建线程对象开启线程
new Thread(new Sender()).start();
new Thread(new Receiver()).start();
}
}
//定义类---代表发送端
class Sender implements Runnable{
//发送过程
@Override
public void run() {
try {
//创建UDP发送端对象
DatagramSocket ds=new DatagramSocket();
//创建Scanner类对象
Scanner 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",9090));
//发送数据包
ds.send(dp);
}
}catch (IOException e){
e.printStackTrace();
}
}
}
//定义类---代表线程执行任务信息(接收端)
class Receiver implements Runnable{
//指定接收过程
@Override
public void run() {
try{
//创建UDP接收端对象---监听端口号
DatagramSocket ds=new DatagramSocket(9090);
//创建接收数据的数据包对象
DatagramPacket dp=new DatagramPacket(new byte[1024],1024);
//保证可以一直接收数据
while (true){
//接收数据
ds.receive(dp);
//解析数据包
System.out.println(dp.getAddress());
System.out.println(new String(dp.getData(),0,dp.getLength()));
}
}catch (IOException e){
e.printStackTrace();
}
}
}
聊天窗口出来啦!
4.TCP协议
底层基于流,传输建立连接(三次握手),安全(可靠)传输速度慢
适用场景:上传和下载、聊天等等
Socket/ServerSocket
客户端:
1.创建TCP客户端对象
2.发起连接(指定IP地址和端口号)
3.获取自带字节输出流往服务器端写出数据
4.写出数据
5.通知服务端数据已经发送完毕
6.关流
package cn.tedu.net.upd;
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 {
//创建TCP的客户端对象
Socket s=new Socket();
//发起连接
s.connect(new InetSocketAddress("127.0.0.1",9092));//让线程对象阻塞
//获取自带的字节输出流
//默认往服务器端传输
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();
//关流
s.close();
}
}
服务器端:
1.创建TCP服务器端对象,监听端口号
2.接收连接
3.获取自带字节输入流从客户端来读取数据
4.读取数据
5.通知客户端数据已经读取完毕
6.关流
package cn.tedu.net.upd;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServerSocketDemo {
public static void main(String[] args) throws IOException {
//创建TCP服务端对象--监听端口号
ServerSocket ss=new ServerSocket(9092);
//接收连接
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();
//关流
s.close();
ss.close();
}
}
让线程阻塞的方法—receive()、connect()、accept()、write()、read()
练习
通过TCP实现文件的上传和下载、
客户端:
package cn.tedu.net.upd;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
public class TCPCopyFileClientDemo {
public static void main(String[] args) throws IOException {
//创建TCP客户端的对象
Socket s=new Socket();
//发起连接
s.connect(new InetSocketAddress("127.0.0.1",9010));
//创建代表文件类的对象
File file=new File("E:\\Linux\\CentOS-7-1908");
//创建文件字节输入流对象(来读取外部文件)
FileInputStream fis=new FileInputStream(file);
//获取自带字节输出流对象
OutputStream os=s.getOutputStream();
//把文件名字的长度值发送到服务器端
//文件名的字节数(字节值)
os.write(file.getName().getBytes().length);
//发送文件名内容
os.write(file.getName().getBytes());
//读取外部文件内容
//自建缓冲区--自建数组
byte[] bs=new byte[1024*1024*50];//50MB
int len=-1;
while ((len=fis.read(bs))!=-1){
//边读边写
os.write(bs,0,len);
}
//通知服务器端数据已经发送完毕
s.shutdownOutput();
//关流
fis.close();
s.close();
}
}
服务器端:
package cn.tedu.net.upd;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPCopyFileServerDemo {
public static void main(String[] args) throws IOException {
//创建TCP服务器端对象---监听端口号
ServerSocket ss=new ServerSocket(9010);
//接收连接
Socket s=ss.accept();
//获取自带字节输入流对象
InputStream is=s.getInputStream();
//读取发送文件名内容的长度值---字节值
byte length=(byte) is.read();
//定义一个字节数组来接收文件内容
byte[] bb=new byte[length];
//把客户端发送过来的文件名的内容读取到字节数组里
is.read(bb);
//创建文件字节输出流对象
//从客户端获取文件名称?
FileOutputStream fos=new FileOutputStream("F:\\"+new String(bb));
//读取客户端发送的数据
//自建缓冲区---自荐书组
byte[] bs=new byte[1024*1024*50];
int len=-1;
while ((len=is.read(bs))!=-1){
//边读边写
fos.write(bs,0,len);
}
//通知客户端数据已经接收完毕
s.shutdownInput();
//关流
fos.close();
s.close();
ss.close();
}
}