TCP通信
在JDK中提供了两个类用于实现TCP程序,一个是ServerSocket类,用于表示服务器端,一个是Socket类,用于表示客户端。
通信时,首先创建代表服务器端的ServerSocket对象,该对象相当于开启一个服务,并等待客户端的连接,然后创建代表客户端的Socket对象向服务器端发出连接请求,服务器端响应请求,两者建立连接开始通信。
ServerSocket类(服务器端)
方法
ServerSocket对象负责监听某台计算机的某个端口号,在创建ServerSocket对象后,需要继续调用该对象的accept()方法,接收来自客户端的请求。当执行了accept()方法之后,服务器端程序会发生阻塞,直到客户端发出连接请求,accept()方法才会返回一个Scoket对象用于和客户端实现通信,程序才能继续向下执行。
//服务器对象 ServerSocket server=new ServerSocket(9999); //和客户端创建连接, Socket socket=server.accept();
Socket类(客户端)
ServerSocket对象可以实现服务端程序,但只实现服务器端程序还不能完成通信,此时还需要一个客户端程序与之交互,为此JDK提供了一个Socket类,用于实现TCP客户端程序。
Socket的常用方法
于向服务器端发送数据
在Socket类的常用方法中,getInputStream()和getOutStream()方法分别用于获取输入流和输出流。当客户端和服务端建立连接后,数据是以IO流的形式进行交互的,从而实现通信。
实现TCP 服务器程序
* 表示服务器程序的类 java.net.ServerSocket
* 构造方法:
* ServerSocket(int port)传递端口号
* 很重要的事情:必须要获得客户端的套接字对象Socket
* Socket accept()
*
* 1,创建服务器ServerSocket对象(指定服务器端口号)
* 2,开启服务器了,等待客户端的连接,当客户端连接后,可以获取到连接服务器的客户端Socket对象
* 3,给客户端反馈信息
* 4,关闭流资源
public class TCPServer { public static void main(String[] args) throws IOException { //创建服务器ServerSocket对象(指定服务器端口号) ServerSocket server=new ServerSocket(9999); //和客户端创建连接, 开启服务器了,等待客户端的连接,当客户端连接后,可以获取到连接服务器的客户端Socket对象 Socket socket=server.accept(); //接收客户端发送数据 InputStream in=socket.getInputStream(); byte[] bytes=new byte[1024]; //获取客户端发送的数据 int len=in.read(bytes); //获取ip String ip=socket.getInetAddress().getHostAddress(); System.out.println("ip地址为:"+ip+"客户端发送的数据为"+new String(bytes,0,len)); //回复客户端 //获取字节输出流 OutputStream out=socket.getOutputStream(); //向客户端发送数据 out.write("收到".getBytes()); //释放资源 server.close(); } }
实现客户端服务器程序
实现TCP 客户端,连接到服务器
* 和服务器实现数据交换
* 实现TCP客户端程序的类 java.net.Soket
* 构造方法
* Socket(String host,int port) 传递服务器IP和端口号
* 注意:构造方法只要运行,就会和服务器进行连接,连接失败,抛出异常
* OutputStream getOutputStream() 返回套接字的输出流
* 作用:将数据输出,输出到服务器
* InputStream getInputStream() 返回套接字的输入流
* 作用:从服务器端读取数据
* 客户端服务器数据交换,必须使用套接字对象Socket中的获取的IO流,自己new流,不行
* 1,创建客户端Socket对象,(指定要连接的服务器地址与端口号)
* 2,获取服务器端的反馈回来的信息
* 3,关闭流资源
//客户端TCP public class TCPClient { public static void main(String[] args) throws UnknownHostException, IOException { //创建客户端Socket对象,(指定要连接的服务器地址与端口号) Socket socket=new Socket("127.0.0.1",9999); //获取字节输出流,向客户端发送数据 OutputStream out=socket.getOutputStream(); out.write("你好".getBytes()); //接收服务器端的回复 //获取字节输入流 InputStream in=socket.getInputStream(); byte[] bytes=new byte[1024]; //把流中的数据存储到数组中,并记录读取字节的个数 int len=in.read(bytes); //获取ip地址 String ip=socket.getInetAddress().getHostAddress(); System.out.println("ip为"+ip+"内容"+new String(bytes,0,len)); socket.close();//释放资源 } }
文件上传
/*
* TCP上传服务器
- ServerSocket套接字对象,监听端口8888
- 方法accept()获取客户端的连接对象
- 客户端连接对象获取字节输入流,读取客户端发送图片
- 创建File对象,绑定上传文件夹
判断文件夹存在,不存在,再创建文件夹
- 创建字节输出流,数据目的File对象所在文件夹
- 字节读取图片,字节流将图片写入到目的文件夹中
- 将上传成功返回客户端
- 关闭资源
*/
public class TCPServer { public static void main(String[] args) throws IOException { //创建服务器对象,明确端口号 ServerSocket server=new ServerSocket(9999); //创建于客户端的连接 Socket socket=server.accept(); //明确数据源,显示哪个客户端Socket连接上了服务器 InputStream in=socket.getInputStream(); File file=new File("D:\io0512\server"); if(!file.exists()){ file.mkdirs(); } String filename="oracle"+System.currentTimeMillis()+new Random().nextInt(99999)+".java"; //明确目的地 FileOutputStream fos=new FileOutputStream(file+File.separator+filename); //开始复制 byte[] bytes=new byte[1024]; int len=0; while((len=in.read(bytes))!=-1){ fos.write(bytes,0,len); } //回复客户端 OutputStream out=socket.getOutputStream(); out.write("上传成功".getBytes()); server.close();//释放资源 } }
/*
* 文件上传 客户端
实现步骤:
- Socket套接字连接服务器
- 通过Socket获取字节输出流,写图片
- 使用自己的流对象,读取图片数据源
FileInputStream
- 读取图片,使用字节输出流,将图片写到服务器
- 通过Socket套接字获取字节输入流
读取服务器发回来的上传成功
6.关闭资源
*
* public void shutdownOutput() 禁用此Socket的输出流,间接的相当于告知了服务器数据写入完毕
*/
//客户端TCP public class TCPClient { public static void main(String[] args) throws UnknownHostException, IOException { //创建客户端Socket对象,(指定要连接的服务器地址与端口号) Socket socket=new Socket("127.0.0.1",9999); //获取字节输出流,向客户端发送数据 OutputStream out=socket.getOutputStream(); out.write("你好".getBytes()); //接收服务器端的回复 //获取字节输入流 InputStream in=socket.getInputStream(); byte[] bytes=new byte[1024]; //把流中的数据存储到数组中,并记录读取字节的个数 int len=in.read(bytes); //获取ip地址 String ip=socket.getInetAddress().getHostAddress(); System.out.println("ip为"+ip+"内容"+new String(bytes,0,len)); socket.close();//释放资源 } }
多线程版本
实现服务器端可以同时接收多个客户端上传的文件。
服务器端
public class Upload implements Runnable{ private Socket socket; public Upload(Socket socket){ this.socket=socket; } public void run() { //明确数据源,显示哪个客户端Socket连接上了服务器 InputStream in; try { in = socket.getInputStream(); File file=new File("D:\io0512\server"); if(!file.exists()){ file.mkdirs(); } String filename="oracle"+System.currentTimeMillis()+new Random().nextInt(99999)+".jpg"; //明确目的地 FileOutputStream fos=new FileOutputStream(file+File.separator+filename); //开始复制 byte[] bytes=new byte[1024]; int len=0; while((len=in.read(bytes))!=-1){ fos.write(bytes,0,len); } //回复客户端 OutputStream out=socket.getOutputStream(); out.write("上传成功".getBytes()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
public class Demo01 { public static void main(String[] args) throws IOException { //创建服务器对象 ServerSocket server=new ServerSocket(9999); while(true){ Socket socket=server.accept(); //启动线程,完成与当前客户端的数据交互过程 new Thread(new Upload(socket)).start();//创建线程任务 } } }
客户端
//客户端 public class TCPClient { public static void main(String[] args) throws UnknownHostException, IOException { //创建客户端对象,明确地址和端口号 Socket socket=new Socket("192.168.1.151",9999); //明确数据源 FileInputStream fis=new FileInputStream("D:\背景\1.jpg"); //明确目的地 OutputStream out=socket.getOutputStream();//服务器端 //开始复制 int len=0; byte[] bytes=new byte[1024]; while((len=fis.read(bytes))!=-1){ out.write(bytes,0,len); } //告知服务器数据已经没有了,不读了 socket.shutdownOutput(); //接收服务器回复 InputStream in=socket.getInputStream(); len=in.read(bytes); System.out.println(new String(bytes,0,len)); socket.close();//释放资源 } }