一、Socket的定义
表示 : 一个Socket就是IP地址和端口号(范围是0~65535)组成,简单理解为ip地址加端口号。
(1)套接字(Socket)开发网络应用程序被广泛采用,以至于成为事实上的标准。
(2) Socket是一个抽象概念,一个应用程序通过一个Socket建立一个远程连接,它的内部通过TCP/IP协议把数据传输到网路。
(3)通信的两端都要有Socket,是两台机器间通信的端点。
(4) Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输。
(5) 一般主动发起通信的应用程序属客户端(一个进程监听),等待通信请求的为服务端(另一个进程)
二、TCP通信原理
TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Scoket对象,从而在通信两端形成网络虚拟链路,一旦建立了虚拟的网络链路,两端的程序就可以通过虚拟链路进行通信。
Java对基本TCP协议的网络提供了良好的封装,使用Socket对象来代表两端的通信端口,并通过Socket产生IO流来进行网络通信。
1. 服务器端
java标准提升了ServerSocket来实现对指定的IP和指定端口的监听。
(1) 创建服务器端的Socket对象(ServerScoket)
ServerSocket(int port);
(2) 监听客户端连接,返回一个Socket对象
Socket accept();
(3)获取输入流,读数据,并把数据显示在控制台
InputStream getInputStream();
(4)释放资源
选中代码块(快捷键:shift+alt+z)
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerDemo {
public static void main(String[] args) throws IOException {
//没有指定ip地址,表示在计算机的所有网络接口上进行监听.
//创建服务器端的Socket对象
ServerSocket ss = new ServerSocket(10086);
//监听客户端连接 并返回Socket对象
Socket s = ss.accept();
//获取输入流
BufferedReader reader=new BufferedReader(
new InputStreamReader(s.getInputStream());
String data = reader.readLine();
System.out.println(data);
//释放资源
ss.close();
}
}
2. 客户端
(1)创建客户端的Socket对象(Socket)
Socket(String host,int port);
( 2)获取输出流,写数据
OutputStream getOutputStream();
( 3)释放资源
选中代码块(快捷键:shift+alt+z)
import java.io.OutputStream;
import java.net.Socket;
public class SendDemo {
public static void main(String[] args) throws Exception {
//创建客户端的Socket对象
//Socket(InetAddress address,int port)
// Socket s = new Socket(InetAddress.getByName("192.168.199.148"),10086);
Socket s = new Socket("192.168.199.148",10086); //底层会将地址字符串转换InetAddress对象
//获取输出流
BufferedWriter writer = new BufferedWriter(new
OutputStreamWriter(client.getOutputStream()));
writer.write("hellojava");
//释放资源
s.close();
}
}
3.Socket流
TCP是一种基于流的协议,服务器端和客户端都使用Socket实例进行网络通信,因此,使用InputStream和OutputStream来封装Scket的数据流.
// 用于读取网络数据:
InputStream in = sock.getInputStream();
// 用于写入网络数据:
OutputStream out = sock.getOutputStream();
写入网络数据,必须调用flush()方法。如果不调用,我们的客户端和服务器端可能会收不到数据,这样做的目的是为了提高传输效率。因为并不是一写入就立刻发送到网络,而是先写入缓冲区,直到缓冲区满了以后,才会一次性发送到网络。
三、 应用案例
例:上传一张照片
服务器端(需要一个输入缓冲流和一个输出缓冲流)
输入流:读取来自客户端发送的图片文件流
输出流:写入本地图片
public class ServerTest {
public static void main(String[] args) {
//服务器端
try {
ServerSocket server=new ServerSocket(8848);
//服务器进入等待状态
//如果有客户端连接时,该方法返回此客户端的Socket
Socket client=server.accept();
//真正ip地址
InetAddress clientNetAddress= client.getInetAddress();
System.out.println(clientNetAddress);
// System.out.println(clientNetAddress.getHostAddress());
//字符串地址
System.out.println("客户端"+clientNetAddress.getHostAddress()+"开始连接........");
//接收来自客户端上传的图片
//输入流:读取来自客户端发送的图片文件流
//输出流:写入本地图片
String imageName=clientNetAddress.getHostAddress().replace("\\.", "-");
try (InputStream in = client.getInputStream();
BufferedInputStream bis = new BufferedInputStream(in);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:\\娱乐\\"+imageName+".jpg"))) {
//每次读取来自客户端的图片文件流
//写入本地
byte[] buff=new byte[1024];
int len=-1;
while((len=bis.read(buff))!=-1) {
bos.write(buff, 0, len);
}
System.out.println("图片读取完毕");
//输出提示信息=》客户端
try( BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(client.getOutputStream()))){
writer.write("successed!!");
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}}
客户端(需要一个输入缓冲流和一个输出缓冲流)
public class Demo {
public static void main(String[] args) {
// 192.168.254.149
// 客户端
try (Socket s = new Socket("192.168.43.15", 8848);
OutputStream out = s.getOutputStream();
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream("D:\\OneDrive\\图片\\本机照片\\青海.jpg"))) {
byte[] buffer = new byte[1024];
int len = -1;
while ((len = bis.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
// "输出"暂时结束(Socket没有关闭)
s.shutdownOutput();
// 来自于服务器的反馈
try (BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream()))) {
String reply = reader.readLine();
System.out.println("服务器的反馈:" + reply);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
四. TCP 网络通讯不为人知的秘密
当客户端连接到服务端后,实际上客户端也是通过一个端口和服务端进行通讯的,这个端口是TCP/IP来分配的,是不确定的,是随机的.