Java基础---网络编程

1、网络模型:OSI参考模型和TCP/IP参考模型

这里写图片描述

通常用户操作的是应用层,而编程人员需要做的是传输层和网际层,用户在应用层操作的数据,经过逐层封包,最后到物理层发送到另一个模型中,再进行逐层解包,图示为:
![package1](https://img-blog.csdn.net/20150812000227184)

2、网络通信三要素:IP地址,端口号,传输协议

1.IP地址

 1. 它是网络中的设备标识
 2. 不易记忆,可用主机名表示,两者存在映射关系
 3. 本机回环地址:127.0.0.1,主机名为:localhost。

IP地址:java中对应的是InetAddress类,存在于java.net包中。

InetAddress类:
(一)无构造函数,可通过getLocalHost()方法返回本地主机获取

InetAddress对象,此方法是静态的。
InetAddress i = InetAddress.getLocalHost();

(二)方法:

1. static InetAddress getByName(String host):获取指定主机的IP和主机名。(最好用ip地址去获取,主机名需要解析)

2. static InetAddress[] getAllByName(String host):在给定主机名的情况下,根据系统上配置的名称服务返回IP地址所组成的数组。返回对象不唯一时,用此方法。

3. String getHostAddress():返回IP地址字符串文本形式,以IP地址为主。

4. String getHostName():返回IP地址主机名。

(三)如何获取任意一台主机的IP地址对象:

1. 功能:返回InetAddress对象

2. 对于任意主机,需要指定传入主机名的参数

注意:如果IP地址和对应的主机名,这种映射关系没有在网络上,就不会解析成功,返回的还是指定的IP。

import java.net.InetAddress;
import java.net.UnknownHostException;

public class IpDemo {

    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        //获取我的本机信息
        InetAddress ip = InetAddress.getByName("LQX");
    //本机名和IP的打印
        System.out.println("IP:"+ip.getHostAddress()+"\tname="+ip.getHostName());
        //这个是我在hosts文件中定义的一个对应关系
        InetAddress ip2 = InetAddress.getByName("www.lqx.com");
        System.out.println("IP:"+ip2.getHostAddress()+"\tname:"+ip2.getHostName());
        //查询百度网站的IP,百度应该不止有一个主机
         InetAddress[] baidu=InetAddress.getAllByName("www.baidu.com");  
            for (InetAddress b :baidu)  
            {  
                String baddress=b.getHostAddress();  
                String bname=b.getHostName();  
                System.out.println("baiduIP="+baddress+"\tbaiduname="+bname);  
            }  
    }

}

打印结果:
ip

2.端口号

1. 定义:

     随着计算机网络技术的发展,原来物理上的接口(如键盘、鼠标、网卡、显示卡等输入/输出接口)已不能满足网络通信的要求,TCP/IP协议作为网络通信的标准协议就解决了这个通信难题。TCP/IP协议集成到操作系统的内核中,这就相当于在操作系统中引入了一种新的输入/输出接口技术,因为在TCP/IP协议中引入了一种称之为"Socket(套接字)"应用程序接口。有了这样一种接口技术,一台计算机就可以通过软件的方式与任何一台具有Socket接口的计算机进行通信。端口在计算机编程上也就是"Socket接口"。

a、用于标识进程的逻辑地址,不用进程的标识。
b、有效端口:0 ~65535,系统使用或保留的端口是:0~ 1024。

3.传输协议

即通信规则,包含TCP和UDP协议

一. UDP(User Datagram Protocol)用户数据报协议

1.  一种无连接的传输层协议,位于第四层——传输层,处于IP协议的上一层

2. 当报文发送之后,是无法得知其是否安全完整到达的

3. 资源消耗小,处理速度快的优点

所以通常音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。比如我们聊天用的ICQ和QQ就是使用的UDP协议。
二. TCP(Transmission Control Protocol 传输控制协议)

1. 一种面向连接的、可靠的、基于字节流的传输层通信协议,位于第四层——传输层,和UDP协议位于同一层

2. 通过三次握手完成连接,是可靠的协议

3. 必须建立连接,效率稍慢

TCP三次握手的过程如下:
(1)
客户端发送报文给服务器进入SEND状态。

(2)
服务器端收到报文,回应一个ACK报文,进入RECV状态。

(3)
客户端收到服务器端的SYN报文,回应一个ACK报文,进入Established
建立状态。

3、JAVA的UDP和TCP编程

1.Socket套接字

1. 用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信

2.它被称之为插座,相当于港口一样,是网络服务提供的一种机制。

3.通信两端都要有Socket,才能建立服务。


4.网络通信其实就是Socket间的通信,数据在两个Socket间通过IO传输。

2.UDP传输

在Java API中,实现UDP方式的编程,包含客户端网络编程和服务器端网络编程,主要由两个类实现,分别是:

1. DatagramSocket:UDP客户端编程涉及的步骤也是4个部分:建立连接、发送数据、接收数据和关闭连接。

DatagramSocket ds = new DatagramSocket();
这样就建立了一个链接,但是没有指定端口,系统会使用未被占用的端口,一般常用来做发送端。
DatagramSocket receive = new DatagramSocket(10001);
这种定义常用来做接收端,他会一直监听10001端口。

2. DatagramPacket:这个类中封装了许多传输的信息,对象中包含发送到的地址、发送到的端口号以及发送的内容等。

DatagramPacket dp = new DatagramPacket(byte[] buf, int length, InetAddress address, int port) ;
IO编程在UDP方式的网络编程中变得不是必须的内容。

接着,介绍一下UDP客户端编程中发送数据的实现。在UDP方式的网络编程中,IO技术不是必须的,在发送数据时,需要将需要发送的数据内容首先转换为byte数组,然后将数据内容、服务器IP和服务器端口号一起构造成一个DatagramPacket类型的对象,这样数据的准备就完成了,发送时调用网络连接对象中的send方法发送该对象即可。
/***
 * UDP发送端:
 * 需求:通过udp传输方式,将一段文字数据发送出去
 */
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

public class Send {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub

        //1.获取目标地址(本机地址)
        InetAddress ip = InetAddress.getLocalHost();
        //2.发送端的声明
        DatagramSocket send = new DatagramSocket();

        //3.要发送的字符串
        String s = "Hello my name is Luan";
        //转byte
        byte []b = s.getBytes();
        //4.传送字节数组b,目标地址为本机,端口10000
        DatagramPacket packet = new DatagramPacket(b, b.length, ip, 10000);

        //5.使用DatagramSocket类中的Send方法发送数据包
        send.send(packet);
        //6.资源关闭
        send.close();
    }

}


/***
 * UDP接收端
 * 需求:定义一个应用程序,用于接收udp协议传输的数据并处理。 
 */
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class Receive {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        //1.接收端需要提供端口,实时监听
        DatagramSocket recv = new DatagramSocket(10000);
        //2.定义数据包,用于存储数据
        byte b[] = new byte[1024];
        //定义收到的包是放在字节数组b里的
        DatagramPacket packet = new DatagramPacket(b, b.length);
        //3.receive方法获取数据包
        recv.receive(packet);//阻塞式方法:没有数据就不继续往下执行,至到得到数据。
        String s = new String(b, 0, packet.getLength());
        System.out.println(packet.getAddress()+"::"+packet.getPort()+"::"+s);
        //4.关闭资源
        recv.close();
    }

}

udp1
信息传过来了,ip地址是没有问题的,我上的校园网分发的IP就是他。端口号是发送端的端口号,没有问题。

/***
 * UDP的发送端
 * 需求:用键盘录入的方式,来发送数据 
 */
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

public class InputSend {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub


        //1.获取目标地址(本机地址)
        InetAddress ip = InetAddress.getLocalHost();
        //2.发送端的声明
        DatagramSocket send = new DatagramSocket();
        DatagramPacket packet = null;
        //3.输入的字符读取到内存
         BufferedReader in
           = new BufferedReader(new InputStreamReader(System.in));
         String s =null;
         while((s=in.readLine())!=null)
         {
                //如果发的是“88”,则资源关闭
                if(s.equals("88"))
                {
                    break;
                }
                //转byte
                byte []b = s.getBytes();
                //传送字节数组b,目标地址为本机,端口10000
                packet = new DatagramPacket(b, b.length, ip, 10000);
                //使用DatagramSocket类中的Send方法发送数据包
                send.send(packet);
         }
         send.close();
    }
}

/***
 * 接收端
 */
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class InputReceive {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub

        //1.接收端需要提供端口,实时监听
                DatagramSocket recv = new DatagramSocket(10000);
                //2.定义数据包,用于存储数据

                while(true)
                {
                    byte b[] = new byte[1024];
                    //定义收到的包是放在字节数组b里的
                    DatagramPacket packet = new DatagramPacket(b, b.length);
                    //3.receive方法获取数据包
                    recv.receive(packet);//阻塞式方法 :没有数据就不继续往下执行,至到得到数据。
                    String s = new String(b, 0, packet.getLength());
                    System.out.println(packet.getAddress()+"::"+packet.getPort()+"::"+s);
                }
    }
}

发送端:
这里写图片描述
接收端:
这里写图片描述

/***
 *需求:UDP的客户端的聊天程序
 *需要用到线程的使用:发送端和接收端分别做成两个线程
 *共同组成了这个客户端的进程
 */
import java.io.*;
import java.net.*;

public class UDPTalk {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Send s1 = new Send();
        receive r1 = new receive();
        Thread t1 = new Thread(s1);
        Thread t2 = new Thread(r1);
        t1.start();
        t2.start();

    }

}
//接收端
class Send implements Runnable {
    private DatagramSocket send = null;
    private DatagramPacket packet = null;
    @Override
    public void run() {
        // TODO Auto-generated method stub
        try {
            InetAddress ip = InetAddress.getLocalHost();
            send = new DatagramSocket();
            BufferedReader in = 
                    new BufferedReader(new InputStreamReader(System.in));
             String s =null;
             while((s=in.readLine())!=null)
             {
                    //如果发的是“88”,则资源关闭
                    if(s.equals("88"))
                    {
                        break;
                    }
                    //转byte
                    byte []b = s.getBytes();
                    //传送字节数组b,目标地址为本机,端口10000
                    packet = new DatagramPacket(b, b.length, ip, 10000);
                    //使用DatagramSocket类中的Send方法发送数据包
                    send.send(packet);
             }
             send.close();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            throw new RuntimeException("发送数据失败"); 
            //System.out.println("目的主机无效!");
        } 
    }
}

//接收端
class receive implements Runnable
{
    private DatagramSocket recv = null;
    private DatagramPacket packet = null;
    @Override
    public void run() {
        // TODO Auto-generated method stub
        //1.接收端需要提供端口,实时监听
        try {
            recv = new DatagramSocket(10000);
            while(true)
            {
                byte b[] = new byte[1024];
                //定义收到的包是放在字节数组b里的
                DatagramPacket packet = new DatagramPacket(b, b.length);
                //3.receive方法获取数据包
                recv.receive(packet);//阻塞式方法 :没有数据就不继续往下执行,至到得到数据。
                String s = new String(b, 0, packet.getLength());
                System.out.println(packet.getAddress()+"::"+packet.getPort()+"::"+s);
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
             throw new RuntimeException("接收端接收数据失败");  
        }
    }   
}

udp3.0
只能自己和自己聊了,如果想和别人聊,那么要把目标IP改为广播地址。
## 标题 ##
比如我这个就应该是111.114.116.255,那么大家都往这个IP发送内容的话就可以一起聊天了。

2.TCP传输

TCP传输,需要明确的区分客户端和服务端。

  1. 客户端使用的类是:Socket,他的构造方法会指定目标地址和端口;
    Socket client1 = new Socket(InetAddress address, int port);

    两个基本方法:
    public InputStream getInputStream():返回此套接字的输入流,Socket对象调用

    public OutputStream getOutputStream():返回套接字的输出流,Socket对象调用

  2. 服务器端使用的类:ServerSocket,他的构造方法只需制定需要监听的端口号即可。
    ServerSocket server = new ServerSocket(int port);
    基本方法:
    public Socket accept():返回值是一个Socket对象,也就是说在服务器端开辟了一个空间,这个空间专门为对应的客户端服务。可以理解为,只要客户端对服务器有请求,那么在服务器就会获取这个客户端的Socket对象,并使用这个服务器端的客户端Socket对象与客户端交流。

/***
 * 客户端代码
 * 需求:客户端给服务端发送数据,服务端收到后,给客户端反馈信息。
 */
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        //目标IP获取
        InetAddress ip = InetAddress.getLocalHost();
        //1.建立客户端Socket,指定目的主机和端口  
        Socket client1 = new Socket(ip, 10000);
        //2.获取Socket流中输出流,发送数据
        OutputStream ou = client1.getOutputStream();
        String s = "这是我的第一个TCP编程!";
        byte b[] = s.getBytes();
        ou.write(b);

        //对服务器返回的数据进行接收
        InputStream in =client1.getInputStream();
        byte b2[] = new byte[1024];
        int len2 = in.read(b2);
        String s2 = new String(b2, 0, len2);
        System.out.println(s2);

        client1.close();
    }
}

/***
 * 服务器端
 *需求: 响应客户端的请求
 */
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) throws IOException {
        // TODO Auto-generated method stub
        //1.服务端使用的是ServerSocket类
        ServerSocket server = new ServerSocket(10000);
        //2.accept方法会获得一个Socket对象,并侦听此对象
        Socket client = server.accept();
        //3、获取对应客户端对象的读取流读取发过来的数据,并打印
        InputStream in = client.getInputStream();
        byte b[] = new byte[1024];
        int len = in.read(b);
        String s = new String(b, 0, len);
        System.out.println(s);

        //对客户端的回复
        OutputStream ou = client.getOutputStream();
        ou.write("我是服务器,收到了".getBytes());
        server.close();
    }
}

服务器端显示收到了:
这里写图片描述
客户端收到了服务器端的响应:
这里写图片描述

/***
 * 练习 
 * 需求:建立一个文本转换服务器 
 * 客户端给服务端发送文本,服务端会将文本转成大写再返回给客户端。 
 * 而且客户端可以不断的进行文本转换。当客户端输入over时,转换结束。
 */
import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;

public class UpCaseClient1 {

    public static void main(String[] args) throws IOException, IOException {
        // TODO Auto-generated method stub

        //创建socket服务
        Socket client = new Socket("127.0.0.1", 10000);

         //定义目的,将数据写入到Socket输出流。发给服务端  
        PrintWriter pw = new PrintWriter(client.getOutputStream(), true);

        //定义读取键盘数据的流对象
        BufferedReader br1 = 
                new BufferedReader(new InputStreamReader(System.in));

        //定义一个Socket读取流,读取服务端返回的大写信息。
        BufferedReader br2 = 
                new BufferedReader(new InputStreamReader(client.getInputStream()));

        String s = null;
        String ret = null;
        while((s=br1.readLine())!=null)
        {
            //判断,是“over”,结束
            if(s.equals("over"))
            {
                break;
            }else{
                pw.println(s);//发送
                ret = br2.readLine();//读取返回的信息
                System.out.println(ret);
            }
        }
        client.close();
    }
}


/**
 * 服务器端
 */
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class UpCaseServer1 {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        //创建服务端的ServerSocket服务,并指定监听端口 
        ServerSocket server = new ServerSocket(10000);

        //获取客户端连接
        Socket client1 = server.accept();

        //读取Socket流中的数据  
        BufferedReader br1 = 
                new BufferedReader(new InputStreamReader(client1.getInputStream()));

         //将大写数据写入到Socket输出流,并发送给客户端。
        PrintWriter pw = new PrintWriter(client1.getOutputStream(), true);
        String s = null;
        while((s = br1.readLine())!=null)
        {
            if(s.equals("over"))
            {
                break;
            }else{
                //将读到数据转换为大写后返回 
                s = s.toUpperCase();
                pw.println(s);
                System.out.println(s);
            }
        }
        server.close();
    }
}

这里写图片描述

这里遇到的问题主要是:由于Writer类实现了Flushable接口,调用 flush 方法将所有已缓冲输出写入底层流。
所以,出现的两边都在等待的问题,第一点就是因为,数据没有实时刷新造成的,那么需要调用flush方法手动刷进去。

错误案例,客户端和服务器端都没有反应

/**客户端
*/
import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;

public class UpCaseClient1 {

    public static void main(String[] args) throws IOException, IOException {

        //创建socket服务
        Socket client = new Socket("127.0.0.1", 10000);

         //定义目的,将数据写入到Socket输出流。发给服务端  
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));

        //定义读取键盘数据的流对象
        BufferedReader br1 = 
                new BufferedReader(new InputStreamReader(System.in));

        //定义一个Socket读取流,读取服务端返回的大写信息。
        BufferedReader br2 = 
                new BufferedReader(new InputStreamReader(client.getInputStream()));

        String s = null;
        String ret = null;
        while((s=br1.readLine())!=null)
        {
            //判断,是“over”,结束
            if(s.equals("over"))
            {
                break;
            }else{
                bw.write(s+"\r\n");
                //bw.newLine();//换行  
                //bw.flush();//此处是重点,如果此处不打开,那么数据将会不再刷新出去,那么客户端和服务器端都在等待。
                ret = br2.readLine();//读取返回的信息
                System.out.println(ret);
            }
        }
        client.close();
    }
}

/**
 * 服务器端
 */
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class UpCaseServer1 {

    public static void main(String[] args) throws IOException {
        //创建服务端的ServerSocket服务,并指定监听端口 
        ServerSocket server = new ServerSocket(10000);

        //获取客户端连接
        Socket client1 = server.accept();

        //读取Socket流中的数据  
        BufferedReader br1 = 
                new BufferedReader(new InputStreamReader(client1.getInputStream()));

         //将大写数据写入到Socket输出流,并发送给客户端。
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client1.getOutputStream()));
        String s = null;
        while((s = br1.readLine())!=null)
        {
            if(s.equals("over"))
            {
                break;
            }else{
                //将读到数据转换为大写后返回 
                s = s.toUpperCase();
                //pw.println(s);
                bw.write(s+"\r\n");
                //bw.newLine();//换行  
                //bw.flush();//此处重点同上
                System.out.println(s);

            }
        }
        server.close();
    }
}

问题:

上面的代码运行不了,归根结底就是因为,Write继承了接口 Flushable,那么,每次服务器读取一行,如果读不到换行标志,则等待;客户端读取键盘输入,读取后不使用flush方法刷出去,那么积压住,两边都等待,造成两边都是等待的问题

解决办法:

1.手动添加换行标志。
2.使用PrintWriter pw = new PrintWriter(client.getOutputStream(), true);treu的意思为自动刷新,且提供prinlln()方法,免去了手动添加换行和刷新的麻烦。
/***
 * 需求:向服务器上传一个文件,服务返回一条信息 
 * 1、客户端:
 * 源:硬盘上的文件;目的:网络设备,即网络输出流。
 * 若操作的是文本数据,可选字符流,并加入高效缓冲区。若是媒体文件,用字节流。

 * 2、服务端:
 * 源:socket读取流;目的:socket输出流。
 * 
 * 3、出现的问题: 
 * 现象:
 * a、文件已经上传成功了,但是没有得到服务端的反馈信息。
 * b、即使得到反馈信息,但得到的是null,而不是“上传成功”的信息
 * 
 * 原因:
 * a、因为客户端将数据发送完毕后,由于双发并没有指定结束标志,那么服务端仍然在等待读取数据,双方都在等待。
 * b、上个问题解决后,收到的不是指定信息而是null,是因为服务端写入数据后,需要刷新,才能将信息反馈给客服端。
 * 
 * 解决a:
 * 方法一:定义结束标记,先将结束标记发送给服务端,让服务端接收到结束标记,然后再发送上传的数据。但是这样定义可能会发生定义的标记和文件中的数据重复,而导致提前结束。
 * 方法二:定义时间戳,由于时间是唯一的,在发送数据前,先获取时间,发送完后在结尾处写上相同的时间戳,在服务端,接收数据前先接收一个时间戳,然后在循环中判断时间戳以结束标记。
 * 方法三:通过socket方法中的shutdownOutput(),关闭输入流资源,从而结束传输流,以给定结束标记。通常用这个方法。
 * 解决b:
 * 方法一:若使用 BufferedWriter bwout=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));  则需要调用flush()方法刷新
 * 方法二:直接使用PrintWriter pw2 = new PrintWriter(client.getOutputStream(),true);自动刷新。
 */

import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;

/***
 * 练习 
 * 需求:向服务器上传一个文件,服务器返回一条信息 
 * @author LQX
 *
 */
public class UpLoadClient {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub

        Socket client = new Socket("127.0.0.1", 10000);
        //文件的读取
        BufferedReader br1 = 
                new BufferedReader(new FileReader("f:\\DemoClass.java"));

        //定义目的,将数据写入到Socket数据流中,并发送给服务端
        //此处我设置自动刷新,方便操作,也可以使用BufferedReader,那么后面就必须手动刷新
        PrintWriter pw = new PrintWriter(client.getOutputStream(), true);

        //读取Socket读取流中的数据 
        BufferedReader br2 = 
                new BufferedReader(new InputStreamReader(client.getInputStream()));

        String s = null;

        while((s = br1.readLine())!=null)
        {
            pw.println(s);
        }
        /**
         * 通过socket方法中的shutdownOutput(),关闭输入流资源,
         * 从而结束传输流,以给定结束标记。通常用这个方法。
         * 不加这个,那么,服务器端没有结束标志,仍然等待客户端发送数据。
         */
        client.shutdownOutput();//关闭客户端的输出流。相当于给流中加入一个结束标记-1. 
        System.out.println(br2.readLine());
        client.close();
    }
}


/***
 * 服务器端
 * 主要使用了PrintWriter(OutputStream out, boolean autoFlush) 构造方法
 * 直接指定了自动刷新,比较方便
 * 
 */
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class UpLoadServer {
public static void main(String[] args) throws IOException {
    ServerSocket server = new ServerSocket(10000);
    //获取客户端链接
    Socket client = server.accept();

    //读取Socket读取流中的数据  
    BufferedReader br = 
            new BufferedReader(new InputStreamReader(client.getInputStream()));

    //
    PrintWriter pw1 = new PrintWriter(new FileWriter("f:\\Copy.txt"),true);

    //将返回信息写入Socket流的写入流中  
    PrintWriter pw2 = new PrintWriter(client.getOutputStream(),true);
    String s = null;
    while((s=br.readLine())!=null)
    {
        System.out.println(s);
        pw1.println(s);
    }
    pw2.println("接收成功!");
    server.close();
}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值