Java多线程下的网络通信编程--图片传输

来源:互联网 发布:金庸武侠知乎 编辑:程序博客网 时间:2024/06/11 10:08

一、网络通信的两种方式

  1. TCP(传输控制协议)
    TCP方式就类似于拨打电话,使用该种方式进行网络通讯时,需要建立专门的虚拟连接,然后进行可靠的数据传输,如果数据发送失败,则客户端会自动重发该数据。
  2. UDP(用户数据报协议)
    UDP方式就类似于发送短信,使用这种方式进行网络通讯时,不需要建立专门的虚拟连接,传输也不是很可靠,如果发送失败则客户端无法获得

二、TCP与UDP的区别

两种传输方式都是实际的网络编程中进行使用,重要的数据一般使用TCP方式进行数据传输,而大量的非核心数据则都通过UDP方式进行传递,在一些程序中甚至结合使用这两种方式进行数据的传递。由于TCP需要建立专用的虚拟连接以及确认传输是否正确,所以使用TCP方式的速度稍微慢一些,而且传输时产生的数据量要比UDP稍微大一些。

TPC和UDP协议的区别

  1. 使用UDP时,每个数据报中都给出了完整的地址信息,因此无需要建立发送方和接收方的连接。
  2. 对于TCP协议,由于它是一个面向连接的协议,在socket之间进行数据传输之前必然要建立连接,所以在TCP中多了一个连接建立的时间
  3. 使用UDP传输数据时是有大小限制的,每个被传输的数据报必须限定在64KB之内。
  4. TCP没有这方面的限制,一旦连接建立起来,双方的socket就可以按统一的格式传输大量的数据。
  5. UDP是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方。
  6. TCP是一个可靠的协议,它确保接收方完全正确地获取发送方所发送的全部数据
  7. TCP在网络通信上有极强的生命力,例如远程连接(Telnet)和文件传输(FTP)都需要不定长度的数据被可靠地传输。相比之下UDP操作简单,而且仅需要较少的监护,因此通常用于局域网高可靠性的分散系统中client/server应用程序

三、实例

下面的实例是基于TCP协议完成的
首先,我们要有一个服务端Server

package com.webpic.test;import java.net.InetAddress;import java.net.InetSocketAddress;import java.net.ServerSocket;/** * 服务端 * @author zkc * */public class Server {    /**     * @param args     */    public static void main(String[] args) {        // TODO Auto-generated method stub        try {            //创建套接字对象            ServerSocket ss = new ServerSocket();            //将套接字绑定到指定的ip地址(由于我是一台机器,所以我指定的是自己的ip地址),并指定端口号(9090)            ss.bind(new InetSocketAddress(InetAddress.getByName("192.168.8.54"),9090));            //启动连接线程            new Thread(new Connect(ss)).start();        } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }}

接着是接收连接对象类

package com.webpic.test;import java.net.ServerSocket;import java.net.Socket;/** * 接收连接对象类 * @author zkc * */public class Connect implements Runnable {    //套接字对象    private ServerSocket ss;    public Connect(ServerSocket ss){        this.ss = ss;    }    @Override    public void run() {        // TODO Auto-generated method stub        try {            //等待用户连接(这里写true意思是让服务端一直等待,直到有人连接)            while(true){                System.out.println("等待用户连接");                //侦听并接受到此套接字的连接                Socket conn = ss.accept();                //在控制台输出谁连接成功了                System.out.println(conn.getInetAddress().getHostAddress()+"连接成功");                //启动传输图片线程                new Thread(new SendPic(conn)).start();            }        } catch (Exception e) {            // TODO: handle exception            e.printStackTrace();        }    }}

然后是传输图片类

package com.webpic.test;import java.io.FileInputStream;import java.io.InputStream;import java.io.OutputStream;import java.net.Socket;import java.util.Scanner;/** * 传输图片类 * @author zkc * */public class SendPic implements Runnable {    //客户端套接字    private Socket conn;    public SendPic(Socket conn){        this.conn = conn;    }    @Override    public void run() {        // TODO Auto-generated method stub        try {            System.out.println("请输入要传输的图片名称");            Scanner sc = new Scanner(System.in);            String name = sc.nextLine();            //创建文件输入流对象fis,图片要传输出去,首先要从文件中读取,所以是创建输入流            FileInputStream fis = new FileInputStream("C:\\Users\\zkc\\Desktop\\zkc\\"+name+".jpg");            //获取输出流对象os            OutputStream os = conn.getOutputStream();            //将图片存入byte数组            byte[] b = new byte[1024];            int nRead = 0;            while((nRead = fis.read(b))!=-1){                //写入输出流                os.write(b,0,nRead);            }            //禁用此套接字的输出流            conn.shutdownOutput();            //获取服务端输入流对象is与客户端对应的输出流对象os中的信息            InputStream is = conn.getInputStream();            byte[] recv = new byte[1024];            System.out.println(new String(recv, 0, is.read(recv)));        } catch (Exception e) {            // TODO: handle exception            e.printStackTrace();        }    }}

服务端的编写就OK了,接下来是客户端,相比于服务端,客户端就比较简单了。

首先是客户端

package com.webpic.test;import java.net.Socket;import java.util.Random;/** * 客户端 * @author zkc * */public class Client {    /**     * 生成随机图片名称方法     * @param length     * @return String     */    public static String getRandomString(int length) {        char[] chr = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};        Random random = new Random();        StringBuffer buffer = new StringBuffer();        for (int i = 0; i < length; i++) {            buffer.append(chr[random.nextInt(36)]);        }        return buffer.toString();    }    /**     * @param args     */    public static void main(String[] args) {        // TODO Auto-generated method stub        try {            //客户端套接字对象并与服务端ip和端口绑定            Socket s = new Socket("192.168.8.54",9090);            //启动线程            new Thread(new ReceivePic(s)).start();        } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }}

其次就是接收图片类

package com.webpic.test;import java.io.File;import java.io.FileOutputStream;import java.io.InputStream;import java.io.OutputStream;import java.net.Socket;import com.web.bean.clientpic;/** * 接收图片类 * @author zkc * */public class ReceivePic implements Runnable{    private Socket conn;    public ReceivePic(Socket conn){        this.conn = conn;    }    @Override    public void run() {        // TODO Auto-generated method stub        try {            InputStream is = conn.getInputStream();            OutputStream os = conn.getOutputStream();            File file = new File("G:\\image");            //路径是否存在,不存在则创建            if(!file.exists()){                file.mkdirs();            }            //创建文件输出流对象fos,也就是传输过来的图片,并生产随机的名字            FileOutputStream fos = new FileOutputStream(file.getAbsolutePath()+"\\"+clientpic.getRandomString(40)+".jpg");            byte[] b = new byte[1024];            int nRead = 0;            while((nRead = is.read(b))!=-1){                //写入图片                fos.write(b,0,nRead);            }            //关闭流            fos.close();            //给服务端相应输入流发送信息            os.write("传输成功".getBytes());            //禁用套接字的输出流            conn.shutdownOutput();        } catch (Exception e) {            // TODO: handle exception            e.printStackTrace();        }    }}

以上,客户端和服务端都编写完毕,可以运行了。

以下是运行时的截图
我们传输一张图片这里写图片描述
首先启动服务端
这里写图片描述
再启动客户端,我们发现,自己和自己连接成功了
这里写图片描述
输入相应的图片名字,再打开相应的文件夹查看是否成功
这里写图片描述
这里写图片描述
到这里,我们就完成了该实例。

由于我是在本机上进行测试,所以不能体现出多线程的特点,也就是可以连接多个客户端同时进行图片的传输,不过我们确实是完成了这一项功能,有兴趣的可以自己尝试一下。

阅读全文
0 0
原创粉丝点击