一、什么是Socket编程
Socket是进程通讯的一种方式,即调用这个网络库的一些API函数实现分布在不同主机的相关进程之间的数据交换。socket网络编程主要分为两部分,一个是ServerSocket服务端,一个是Socket客户端,socket网络编程主要就是用这2个类。
二、Socket网络编程入门Demo
代码思路流程:服务端先开启服务,然后等待客户端请求连接,发送和接收消息都是通过io流来实现。
Server.java
package socket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args){
try {
//开启服务,绑定服务端口,默认为本机IP地址+下面传进来的端口号
ServerSocket server = new ServerSocket(9999);
System.out.println("开启服务...等待连接");
//等待客户端连接,判断是否有客户端来进行连接
Socket socket = server.accept();
System.out.println("与客户端连接成功");
//给客户端发送消息
OutputStream outputStream = socket.getOutputStream();
String message = "hello";
outputStream.write(message.getBytes());
//接收客户端发送来的消息
InputStream inputStream = socket.getInputStream();
byte[] bs = new byte[100];
inputStream.read(bs);
System.out.println("接收来自客户端的消息:"+new String(bs));
//关闭流
outputStream.close();
inputStream.close();
socket.close();
server.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client.java
package socket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args){
try {
Socket socket = new Socket("127.0.0.1",9999);
//接收服务端的消息
InputStream inputStream = socket.getInputStream();
byte[] bs = new byte[100];
//inputStream读到的字节输入到那里去
inputStream.read(bs);
//把字节数组转换为字符串输出
System.out.println("接收来自服务端的消息:"+new String(bs));
//发送给服务端消息
OutputStream outputStream = socket.getOutputStream();
String message = "我是小江";
outputStream.write(message.getBytes());
//关闭流
outputStream.close();
inputStream.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
程序运行截图:
image.png
image.png
三、socket网络编程发送接收文件
代码思路:建立连接这些还是和之前发送接收字符串的一样,变化的是在发送部分的代码上,上面发送字符串可以直接发送,因为变量是存在内存中的,计算机可以直接获取到,而我们文件是存放在本地硬盘的,所以我们要想办法把文件也放到内存中。
硬盘-->内存(相当于发送):直接new一个InputStream,因为不是用来网络请求所以不需要使用socket来获取,同理,内存-->硬盘(相当于接收):直接new一个OutputStream。
服务端发送文件时,通过不断地从硬盘读文件的字节到内存中,存在字节数组里,然后通过socket输出流发送给客户端,客户端接收文件时,通过不断地从内存的字节数组里读取,然后通过socket输入流写入到硬盘中。
Server.java
package socket;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args){
try {
//开启服务,绑定服务端口,默认为本机IP地址+下面传进来的端口号
ServerSocket server = new ServerSocket(9999);
System.out.println("开启服务...等待连接");
//等待客户端连接,判断是否有客户端来进行连接
Socket socket = server.accept();
System.out.println("与客户端连接成功");
//准备要发送的文件
File file = new File("D:\\设计模式 (状态).pdf");
//从硬盘读取到内存中
InputStream fileIn = new FileInputStream(file);
//用于网络发送文件
OutputStream outputStream = socket.getOutputStream();
int len = -1;//传输结束标识
byte[] bs = new byte[1000];//字节缓冲区,每次发送的文件大小100个字节
//循环发送(因为文件一般会大,超过100字节,所以需要循环来分次发送)
while((len=fileIn.read(bs))!=-1){
outputStream.write(bs,0,len);
}
//关闭流
fileIn.close();
outputStream.close();
socket.close();
server.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client.java
package socket;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args){
try {
Socket socket = new Socket("127.0.0.1",9999);
//从内存中读取到硬盘中
OutputStream outputStream = new FileOutputStream("E:\\www.txt");
//用于网络接收文件
InputStream inputStream = socket.getInputStream();
int len = -1;//传输结束标识
byte[] bs = new byte[1000];//字节缓冲区
//循环写入
while ((len = inputStream.read(bs))!=-1){
outputStream.write(bs,0,len);
}
//关闭流
outputStream.close();
inputStream.close();
socket.close();
System.out.println("下载成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
三、对上述程序使用线程进行优化
经过第二点的程序,我们能实现一次发送文件的功能,相当于客户端下载一次服务端的文件,但是我们现在想法是要实现开启服务器,然后我们客户端可以无限下载服务器的文件,我们可以使用循环来做,并且用多线程控制多个请求。通过构造方法把服务端的socket对象拿到。附重构后的代码:
Download.java(线程类,专门用来run事情处理下载功能)
package socket;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Download implements Runnable{
private Socket socket;
public Download(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
//准备要发送的文件
File file = new File("D:\\设计模式 (状态).pdf");
//从硬盘读取到内存中
InputStream fileIn = new FileInputStream(file);
//用于网络发送文件
OutputStream outputStream = socket.getOutputStream();
int len = -1;//传输结束标识
byte[] bs = new byte[1000];//字节缓冲区,每次发送的文件大小100个字节
//循环发送(因为文件一般会大,超过100字节,所以需要循环来分次发送)
while ((len = fileIn.read(bs)) != -1) {
outputStream.write(bs, 0, len);
}
//关闭流
fileIn.close();
outputStream.close();
socket.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
Server.java
package socket;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args){
try {
//开启服务,绑定服务端口,默认为本机IP地址+下面传进来的端口号
ServerSocket server = new ServerSocket(9999);
System.out.println("开启服务...等待连接");
int i = 1;
while (true){
//等待客户端连接,判断是否有客户端来进行连接
Socket socket = server.accept();
System.out.println("与客户端第"+(i++)+"次连接成功");
//下载的线程,Runnable对象不能直接start,所以要Runnable-->Thread对象
new Thread(new Download(socket)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client.java(这个程序是可以发到其他电脑去执行的,更改下服务端IP地址即可到指定IP地址的服务器去下载文件,不过前提是服务器的程序服务有开启先。)
package socket;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args){
try {
Socket socket = new Socket("127.0.0.1",9999);
//从内存中读取到硬盘中
OutputStream outputStream = new FileOutputStream("E:\\设计模式 (状态)copy.pdf");
//用于网络接收文件
InputStream inputStream = socket.getInputStream();
int len = -1;//传输结束标识
byte[] bs = new byte[1000];//字节缓冲区
//循环写入
while ((len = inputStream.read(bs))!=-1){
outputStream.write(bs,0,len);
}
//关闭流
outputStream.close();
inputStream.close();
socket.close();
System.out.println("下载成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
附程序截图(前面3次是我自己本地电脑测试,后面2次是我把客户端程序发给朋友电脑,我自己开服务端程序,然后让他更改IP地址到我这台服务端下载文件,经测试均成功)
image.png附:1、socket编程网络知识1
2、socket编程网络知识2
网友评论