美文网首页
网络编程学习----(3)TCP通讯

网络编程学习----(3)TCP通讯

作者: 艾剪疏 | 来源:发表于2018-08-28 22:00 被阅读17次

    1 演示TCP的传输的客户端和服务端的互访
    2 读取客户端键盘输入流,并在服务端将其转换为大写字符将其返回给客户端。
    3 通过TCP通讯实现文件上传
    4 TCP并发上传图片

    TCP通讯过程较为简单,要经过三次握手,在这期间可以反复的接受和发送数据。

    1 演示TCP的传输的客户端和服务端的互访

    代码如下:

    客户端:

    public static void main(String[] args) {
            try {
                Socket s = new Socket("192.168.0.109",10001);//1 建立socket服务。指定要连接的主机端口
                OutputStream out = s.getOutputStream();//2 获取socket流中的输出流。将数据写到该流中。通过网络发给服务端
                out.write("hello server".getBytes());
                InputStream in = s.getInputStream();//3 获取socket中的输入流,将服务端反馈的数据获取到,并打印
                byte[] buf = new byte[1024];
                int len = in.read(buf);//阻塞式方法,接受服务端返回数据
                System.out.println(new String(buf,0,len));
                s.close();//4 关闭客户端资源
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    

    服务端:

      public static void main(String[] args) {
            try {
                ServerSocket ss = new ServerSocket(10001);
                Socket s = ss.accept();//阻塞式方法,接受客户端输入数据
                String ip = s.getInetAddress().getHostAddress();
                System.out.println(ip+"......conntected");
                InputStream in = s.getInputStream();//读取客户端发送数据
                byte[] buf = new byte[1024];
                int len = in.read(buf);
                System.out.println(new String(buf,0,len));
                OutputStream out = s.getOutputStream();//接收完毕之后,从服务端返回输出语句
                out.write("hello you too client".getBytes());
                s.close();
                ss.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    

    2 读取客户端键盘输入流,并在服务端将其转换为大写字符将其返回给客户端。

    使用缓冲区Buffered

    代码如下:

    客户端:

      public static void main(String[] args){
    
            try {
                Socket s = new Socket("192.168.0.109",10001);
                BufferedReader br =
                        new BufferedReader(new InputStreamReader(System.in));
                BufferedWriter bfwOUT =
                        new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));//字节流转字符流
                BufferedReader brwIN =
                        new BufferedReader(new InputStreamReader(s.getInputStream()));
                String line = null;
                while((line = br.readLine())!=null){
                    if("over".equals(line)){
                        break;
                    }
                    bfwOUT.write(line);
                    bfwOUT.newLine();
                    bfwOUT.flush();
                   //返回服务端返回的大写数据
                    String str = brwIN.readLine();
                    System.out.println(str);
                }
                br.close();
                s.close();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    

    服务端:

       public static void main(String[] args){
            try {
                ServerSocket ss = new ServerSocket(10001);
                Socket s = ss.accept();//阻塞式方法,接受客户端输入数据
                String ip = s.getInetAddress().getHostAddress();
                System.out.println(ip+"......conntected");
                BufferedReader brwIN =
                        new BufferedReader(new InputStreamReader(s.getInputStream()));
                BufferedWriter bfwOUT =
                        new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));//字节流转字符流
                String line = null;
                //从客户端读取,在将其转换为大写字符
                while((line = brwIN.readLine())!=null){
                    bfwOUT.write(line.toUpperCase());
                    bfwOUT.newLine();
                    bfwOUT.flush();
                    System.out.println(line);
                }
               s.close();
                ss.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    

    3 通过TCP通讯实现文件上传

    改变的地方仅仅是读取和输出的方式,由字符流变为了文件流。

    代码如下:

    客户端:

     public static void main(String[] args){
            try {
                Socket s = new Socket("192.168.0.109",10001);
                BufferedReader bufr = new BufferedReader(new FileReader("E:/test/output_res.txt"));//改变的地方
                PrintWriter out = new PrintWriter(s.getOutputStream(),true);//这种输方式会自动刷新,较二中的BufferedWriter更为方便
                String line = null;
                while((line = bufr.readLine())!=null){
                    out.println(line);
                }
                s.shutdownOutput();//结束标记,告诉服务端,服务已结束,可停止
                BufferedReader bufrINT = new BufferedReader(new InputStreamReader(s.getInputStream()));
                String str =  bufrINT.readLine();
                System.out.println(str);
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    

    服务端:

    public static void main(String[] args){
            try {
                ServerSocket ss = new ServerSocket(10001);
                Socket s = ss.accept();//阻塞式方法,接受客户端输入数据
                String ip = s.getInetAddress().getHostAddress();
               System.out.println(ip+"......conntected");
                BufferedReader buFIN = new BufferedReader(new InputStreamReader(s.getInputStream()));
                PrintWriter out = new PrintWriter(new FileWriter("E:/test/111.txt"),true);
                String line = null;
                while((line = buFIN.readLine())!=null){
                    out.println(line);
                }
                PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
                pw.println("上传成功");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    

    4 TCP并发上传图片

    需求:实现服务器多线程上传图片。

    4.1 实现单线程上传图片

    思路:
    1、实现单个线程的图片上传。
    2、优化单线程程序。根据多线程的特点,需要将单个线程上传代码中共性的部分提取出来,多线程执行。

    那么首先实现单线程图片上传程序:

    客户端:

     public static void main(String args[]){
            try {
                //建立连接
                Socket s = new Socket("192.168.0.109",10002);            
                FileInputStream fis = new FileInputStream("E:\\test\\sa.jpg");
                OutputStream out = s.getOutputStream();
                byte []buf = new byte[1024];
    
                int len = 0;
                //读取内容
                while((len = fis.read(buf))!=-1){
                    out.write(buf,0,len);//写入socket流中
                }
                //结束
                s.shutdownOutput();//结束标记
                //服务端回复
                InputStream in = s.getInputStream();
                byte []bufIn = new byte[1024];
                int num = in.read(bufIn);
                System.out.println(new String(bufIn,0,num));
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    

    服务端:

     public static void main(String args[]){
            try {
                //建立连接
                ServerSocket ss = new ServerSocket(10002);          
                Socket s = ss.accept();
                String ip = s.getInetAddress().getHostAddress();
                System.out.println(ip+"......conntected");
                InputStream in = s.getInputStream();
                FileOutputStream fos = new FileOutputStream("H:\\Pictures\\sa1.jpg");
                byte []buf = new byte[1024];
                int len = 0;
    
                while((len = in.read(buf))!=-1){
                    fos.write(buf,0,len);//输出上传内容
                }
                OutputStream out = s.getOutputStream();
                out.write("上传成功".getBytes());
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    

    4.2 多线程上传图片

    好了,分析单线程的图片上传程序可知:在服务端上传过程中读取上传图片部分属于共性部分代码,需要使用多线程操作。

    新建PicThread类实现Runnable接口,用以支持多线程上传。

    代码如下:

    public class PicThread implements Runnable{
        private Socket s;
        PicThread(Socket s){
            this.s = s;
        }
        @Override
        public void run() {
            int count = 1;
            String ip = s.getInetAddress().getHostAddress();
            try {
                InputStream in = s.getInputStream();
                //小代码,实现文件时,多文件的命名
                File file = new File(ip+"("+(count)+")"+".jpg");
                //遍历,直到文件编号不冲突。
                while(file.exists()){
                    file = new File(ip+"("+(count++)+")"+".jpg");
                }
                FileOutputStream fos = new FileOutputStream(file);
                byte []buf = new byte[1024];
                int len = 0;
                while((len = in.read(buf))!=-1){
                    fos.write(buf,0,len);
                }
                OutputStream out = s.getOutputStream();
                out.write("上传成功".getBytes());
            } catch (Exception e) {
                throw new RuntimeException(ip+"....error");
            }
        }
    }
    

    服务端代码调整

    public static void main(String args[]){
            try {
                ServerSocket ss = new ServerSocket(10002);
                //阻塞式方法,循环读取,有文件上传,便不会关闭
                while(true){
                    Socket s = ss.accept();
                    new Thread(new PicThread(s)).start();
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    

    为了上传的方便,在客户端也需要做条件的维护。

    public static void main(String args[]){
            try {
                File file = new File(args[0]);
                if(!(file.exists() && file.isFile())){
                    return;
                }
                if(!file.getName().endsWith(".jpg")){
                    return;
                }
    
                if(file.length()>1024*1024*5){
                    return;
                }
                Socket s = new Socket("192.168.0.109",10002);
                FileInputStream fis = new FileInputStream(file);
                OutputStream out = s.getOutputStream();
                byte []buf = new byte[1024];
                int len = 0;
    
                while((len = fis.read(buf))!=-1){
                    out.write(buf,0,len);//写入socket流中
                }
                s.shutdownOutput();//结束标记
                InputStream in = s.getInputStream();
                byte []bufIn = new byte[1024];
                int num = in.read(bufIn);
                System.out.println(new String(bufIn,0,num));
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    

    1 启动服务端,等待。
    2 启动客户端,上传图片。
    通过这段代码,即可实现多线程上传图片,即多用户并发上传图片。


    END

    相关文章

      网友评论

          本文标题:网络编程学习----(3)TCP通讯

          本文链接:https://www.haomeiwen.com/subject/hzkcwftx.html