黑马程序员---网络编程

网络编程

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------


1.基础知识

多个PC之间如何实现数据传输—利用网络在多个PC之间数据传输。就是Socket编程。

1.1 IP地址

IP地址就像是电话号码:有了某人的电话号码,就能与他通信。同样,有了某台主机的IP地址,就能跟这台机的主人通信了。

当一台计算机与另一台计算机通信时,需要知道另外一台计算机的地址。互联网协议(Internet Protocol)IP 可以用来唯一的标识互联网上的计算机。IP地址由4段点隔开的0~255的十进制数组成 如:192.168.1.1。

IP地址是网络中用于区分不同计算机的数字标识,由32个二进制位组成,并将其分成7组,每组8位。32位的IP地址由于用二进制表示不便于记忆,因而采用了称为点分十进制的方法表示。 如:192.168.1.1

目前IP地址协议的版本号是4(IPv4)下一个版本是ipv6。IPv4采用32位(bit)地址长度,只有大约43亿个地址(2^32)。Ipv6具有更大的地址空间,ipv6中IP地址的长度为128位,即最大地址个数为2^128个。

1.2 域名

因为Ip地址是数字,不容易记忆,所以就将他们映射为域名(domain name);如http://hao.360.cn/

在互联网中有叫域名服务器(DomainName Server DNS)的服务器,它可以返这个域名转换成IP地址,然后根据这个IP地址进行通信。

在命令行中使用:

1.ipconfig 可以查询自己的ip地址

2.ping 尝试连接某个Ip地址

3.特殊ip地址 127.0.0.1本地回路地址主机名:localhost,ping这个地址可以测试网卡是否可用。

1.3 端口号

计算机端口(port)是计算机与外界通信交流的出口。计算机通过端口区分Internet的各种服务。

计算机的每一个程序都会对应一个端口号。例如使用计算机可以进行E-Mail(邮件) www(浏览器) FTP(文件传输) 操作。这些程序都需要互联网进行数据的传输。计算机是通过端口进行判断数据的归属,不同的程序有不同的端口。

端口是有范围限制的,端口号只有整数0~65535。

1)公认端口(wellknow ports)范围是0~1023系统保留商品。

2)注册端口(registered ports)范围1024~49151松散绑定一些服务,虽然有一些服务绑定这些端口,这些端口还可以应用于其他服务。

3)私有/动态端口(private/dynamic ports)范围49152~65535 动态分配是指当一个系统进程或应用程序进程需要网络通信时,它向主机申请一个端口,主机从可用的端口号中分配一个供它使用。当这个进程关闭时,同时也释放了所占的端口号。

4)程序中需要指定商品时,那么尽量使用1024~65535的,1024以下的基本都被系统程序占用了。

互联网协议是在互联网中从一台计算机向另一台计算机传输数据的低层协议,数据是以包的形式封装的。有两个和互联网一起使用的协议是UDP和TCP

1.4 UDP

 User datagram protocol (用户数据报协议)

 特点:

1.无连接、不可靠、速度快;

2.将数据及源和目的封装成数据包中,不需要建立连接;

3.每个数据报的大小在限制在64k以内;

4.UDP协议不能保证传输没有丢失。

应用范围:视频通话,即时通信,IP电话

1.5 TCP

Transmissioncontrol protocol (传输控制协议)

特点:

1.面向连接、可靠、效率稍低;

2.通过三次握手,建立连接,形成传输数据的通道。

3.在连接中进行大数据传输;

4.TCP协议能够发现丢失的传输数据并重新发送。

应用范围:文件传输,接收邮件。

2.Java程序设计的网络编程

Java是通过Socket机制实现网络间的数据通信。

Socket就是为网络服务提供的一种机制。通信的两端都有Socket。网络通信其实就是Socket间通信。数据在两个Socket间通过IO传输。

2.1 InetAddress

既然要使用网络编程,那么IP地址是需要经常使用的,Java提供了一个类来表示IP地址。Java.net.InetAddress类是Java的IP地址封装类,它不需要用户了解如何实现IP地址的细节。

InetAddress类没有构造方法,要创建该类的实例对象,可以通过该类的静态方法获得该对象。

常用方法

2.2 测试方法

获取本地IP地址
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
public class GetLocalHost {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        tssLocalHost();
    }
    public static void tssLocalHost(){
        try {
            //获得本机的IP地址
            InetAddress localHost = InetAddress.getLocalHost();
            //输出InetAddress对象
            System.out.println(localHost);
            //获得IP十进制
            String hostAddress = localHost.getHostAddress();
            System.out.println(hostAddress);
            //获取主机名
            String hostName = localHost.getHostName();
            System.out.println(hostName);
            //ip字节表示形式
            byte[]address = localHost.getAddress();
            System.out.println(Arrays.toString(address));
            //将数字转化为二进制
            System.out.println(Integer.toBinaryString(192));
            System.out.println(Integer.toBinaryString(-64));
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
输出:
EBKFZPUZWJ499IE/192.168.1.4
192.168.1.4
EBKFZPUZWJ499IE
[-64, -88, 1, 4]
11000000
11111111111111111111111111000000
根据域名获取Ip

获取www.baidu.com域名的IP地址

获取www.baidu.com域名的所有IP地址

import java.net.InetAddress;
import java.net.UnknownHostException;
public class TestBaiduIP {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        testBaidu();
    }
    public static void testBaidu(){
        //将百度域名字符串放在方法中获得InetAddress对象
        String host = "www.baidu.com";
        try {
            InetAddress address = InetAddress.getByName(host);
            //获得百度的ip
            String hostAddress = address.getHostAddress();
            System.out.println(hostAddress);
            //获得百度的ip集
            InetAddress [] allAddress = InetAddress.getAllByName(host);
            for(InetAddress i : allAddress){
                System.out.println(i);
            }
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
输出:
115.239.210.27
www.baidu.com/115.239.210.27
www.baidu.com/115.239.210.26

2.3 Java中的UDP

要用到的类

2.3.1 DatagramPacket类

该类是用来表示数据包。

构造函数

在发送数据时,必须指定接收方的Socket地址和端口号,因此使用第二种构造函数可创建发送数据的DatagramPacket对象。

2.3.2 DatagramSocket类

该类表示发送和接收数据包的套接字。

构造函数

第三种构造函数适用于有多块网卡和多个IP地址的情况

2.3.3 UDP发送

1.创建Socket,发送端不需要指定Ip地址和端口,使用本机地址发送,会自动找到未使用的端口。需要使用DatagramSocket此类表示用来发送和接收数据报包的套接字。如

DatagramSocket socket = new DatagramSocket();

2.创建数据包– 使用DatagramPacket

创建数据包需要通过构造函数指定改善的数据(字节数组),数据长度(数组长度),接受方的IP地址(InetAddrss类),接受方端口号(port)

DatagramPacket(byte[]buf , int length, InetAddress address , int port)

3.发送数据–使用Socket类的send方法将数据包发送出去

void send(DatagramPacket p) 从此套接字发送数据包

4.关闭Socket – 使用Socket的close方法关闭

void close()

注:在发送端,在要数据包对象中明确目的地及端口。

2.3.4 UDP接收

1.创建Socket – 接收时必须指定端口号

DatagramSocket socket = new DatagramSocket(8888);
2.创建数据包– 接收时也需要创建数据包,用来存储数据,需要一个字节组
DatagramPacket packet = new DatagramPacket(new byte[1024] , 1024)

3.接收数据– 使用DatagramSocket的receive方法接收数据,该方法需要指定数据包

sock.receive(packet);

4.从数据包中获取数据

Byte[]data = packet.getData();
5.获取数据长度
intlen = packet.getLength()

6.获取发送端IP地址

packet.getInetAddress().getHostAddress()
7.获取发送端口号
packet.getPort()

8.关闭流socket

socket.close()

注意:在接收端,要指定监听的商品

代码实例

练习一

发送端:使用UDP将一串数据发送出去,并使用UDP接收,要求获得发送者的IP地址端口号,并将信息显示出来

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPSend {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("UDP发送端启动,准备发送数据!");
        DatagramSocket socket = null;
        try {
            //创建socket
         socket = new DatagramSocket();
         //创建数据包
         String data = "你好,我是UDP";
         InetAddress ip = InetAddress.getByName("255.255.255.255");
         DatagramPacket packet = new DatagramPacket(data.getBytes(),data.getBytes().length,ip,10002);
         //发送数据
         socket.send(packet);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //关闭socket
        socket.close();
        System.out.println("UDP发送端数据发送完毕!");
    }
}

接收端

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPReceive {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("这是UDP接收端,已经启动,等待接收");
        DatagramSocket socket = null;
        try {
            //创建Socket接收端指定端口号与发送端端口一样
             socket = new DatagramSocket(10002);
             //创建接收的数据包
            byte []by = new byte[1024];
            DatagramPacket packet = new DatagramPacket(by,by.length);
            //接收
            socket.receive(packet);
            //获取发送方的IP
            InetAddress address = packet.getAddress();
            System.out.println(address);
            String hostAddress = address.getHostAddress();
            //获取发送方的端口号
            int port = packet.getPort();
            //获取数据
            byte [] data = packet.getData();
            //获取数据长度
            int dataLen = packet.getLength();
            System.out.println("IP:" + hostAddress + "端口号:" + port + "发送了:" + new String(data,0,dataLen));
           
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //关闭socket
        socket.close();
        System.out.println("接收端接受完毕!");
    }
}
输出:
这是UDP接收端,已经启动,等待接收
/192.168.1.4
IP:192.168.1.4端口号:1696发送了:你好,我是UDP
接收端接受完毕!
练习二:通过控制台录入用户信息,使用UDP发送出去,另外一个UDP进行接收,并使用控制台反馈信息,并循环,实现简单对话,用户输入byte 结束对话。

发送方

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;
public class TestUDPSend {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        // 发送端
        System.out.println("这是UDP发送端,即将发送数据!");
        DatagramSocket socket = null;
        // 创建Socket
        try {
            socket = new DatagramSocket();
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    System.in));
            while (true) {
                System.out.println("请输入发送信息:");
                String message = br.readLine();
                if ("bye".equals(message)) {
                    break;
                }
                //准备数据包,封装数据
                DatagramPacket packet = new DatagramPacket(message.getBytes(),
                        message.getBytes().length, InetAddress
                .getByName("127.0.0.1"), 10007);
                //发送数据
                socket.send(packet);
            }
        } catch (SocketException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally{
            //关闭socket
            socket.close();
        }
        System.out.println("发送端数据发送完毕!");
    }
}
接收端
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class TestUDPReverse {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("这是UDP接收端,准备接收数据");
        //创建socket
        DatagramSocket socket = null;
        try {
            socket = new DatagramSocket(10007);
            //创建数组
            byte[] by = new byte[1024];
            //创建packet
            DatagramPacket packet = new DatagramPacket(by, by.length);
            while (true) {
                //接收数据
                socket.receive(packet);
                //获取发送端IP
                String ip = packet.getAddress().getHostAddress();
                //获取发送方端口
                int port = packet.getPort();
                //获取数据长度
                int dataLen = packet.getLength();
                //获取数据
                byte[] data = packet.getData();
                //转为字符串
                String mess = new String(data, 0, dataLen);
                System.out.println("发送方:" + ip + "端口:" + port + "发送了:" + mess);
                if ("bye".equals(mess)) {
                    break;
                }
            }
        } catch (SocketException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            socket.close();
        }
    }
}

2.4 Java的TCP

2.4.1 概述

特点

1.TCP面向连接,数据安全,区分服务器和客户端;

2.TCP分为Socket(客户端)和ServerSocket(服务器);

3.需要分别和建立客户端和服务器端;

4.客户端和服务器建立连接后,通过Socket中的IO流进行数据的传输;

5.需要关闭socket;

6.客户端与服务器是两个独立的应用程序。

2.4.2 TCP客户端
建立TCP客户端的步骤

1.创建客户端Socket;

需要指定连接到服务器的地址和端口号,并尝试连接,客户端需要服务器的IP地址以及端口,这样才可以去试着建立连接,如果连接失败,会出现异常。

Socket socket = new Socket(“192.168.1.3”,10000);

2.连接成功获取输入输出流;

连接成功,说明客户端与服务端建立了通道,那么通过IO流就可以进行数据的传输,而Socket对象已经提供了输入流与输出流对象,通过getInputStream(),getOutputStream()获取即可。

Socket.getInputStream()
Socket.getOutputStream()

3.将数据写出到服务端;

使用字节输出流的write()方法

4.关闭socket。

调用close方法。

连接成功之后获取输入输出流

Socket.getInputStream(),

Socket.getOutputStream()

获取流之后就可以通过输入输出流发送和读取数据了,客户端的输入流连接服务端输出流,客户端输出流连接服务端输入流。

2.4.3TCP服务端
建立服务端的步骤
  1. 创建服务端

ServerSocket,需要指定端口号。客户端连接的就是这个端口

创建ServerSocket

ServerSocket serverSocket new ServerSocket(10000);

  1. 和客户端建立连接

通过accept()

Socket accept()
           侦听并接收到此套接这的连接

该方法会侦听是否有客户端连接,如果有建立连接,并获取客户端的Socket ,也就是说服务端创建之后可以获取客户端连接,返回一个Socket对象,这个Socket就是和客户端连接的Socket.

Socket socket = serverSocket.accept()
  1. 接受客户端的数据,获取客户端的数据

服务器获取这个socket的输入输出流,就可以和客户端发送接收数据了

Socket.getInputStream()
Socket.getOutputStream()
  1. 获取客户端的IP地址和端口号

使用服务端的Socket获取IP地址和端口

InetAddress getInetAddress()
       返回套接字连接的地址
Int getPort()
       返回此套接字连接到的远程端口
  1. 关闭客户端与服务端

在客户端与服务端分别调用close()

客户端

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class TCPClient {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("客户端启动。。。。");
        Socket socket = null;
        OutputStream out = null;
        try {
            //创建客户端
            socket = new Socket("127.0.0.1",10000);
            //与服务端建立连接,获取输出流
            out = socket.getOutputStream();
            System.out.println("客户端发送数据。。。。");
            //将数据写出服务端
            out.write("TCP,你好我是客户端。。。".getBytes());
                    } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally{
            try {
                //关闭输出流
                out.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
            }
}

  服务端

import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServer {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("服务端启动。。。。");
        ServerSocket server = null;
        Socket socket = null;
        try {
            //服务器,声明同一个监听端口
            server = new ServerSocket(10000);
            //使用accept进入侦听状态,获取客户端数据
            socket = server.accept();
            //获得输入流
            InputStream in = socket.getInputStream();
            //获得客户端IP,端口
            InetAddress inetAddress = socket.getInetAddress();
            String ip = inetAddress.getHostAddress();
            int port = socket.getPort();
            //获取客户端数据
            byte [] by = new byte[1024];
            System.out.println("服务端接受数据:");
            int len = in.read(by);
            String mess = new String(by,0,len);
            System.out.println("客户端:" + ip + ":" + port + "发送了:" + mess);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally{
            try {
                //关闭客户端
                socket.close();
                //关闭服务端
                server.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
                    }
    }
}
输出:
服务端启动。。。。
服务端接受数据:
客户端:127.0.0.1:2934发送了:TCP,你好我是客户端。。。
实例2

客户端与服务端实现交互

 客户端

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class TCPClient {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("客户端启动。。。。。");
        Socket socket = null;
        InputStream in = null;
        OutputStream out = null;
        try {
            //创建客户端
            socket = new Socket("127.0.0.1",10000);
            //与服务端建立连接,获取输入输出流
            in = socket.getInputStream();
            out = socket.getOutputStream();
            while(true){
                //将数据写出到服务端
                System.out.println("客户端发送数据。。。");
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                System.out.println("你说:");
                String line = br.readLine();
                System.out.println("你告诉了服务器:");
                out.write(line.getBytes());
                //获取服务端的回话
                byte [] by = new byte[1024];
                int len = in.read(by);
                System.out.println("服务端告诉我了:");
                System.out.println(new String(by , 0 , len));
                if("bye".equals(line)){
                    break;
                }
            }
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally{
            try {
                //关闭socket
                out.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

服务端

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServer {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("服务器启动:");
        ServerSocket  server = null;
        Socket socket = null;
        InputStream in = null;
        OutputStream out = null;
        InetAddress inetAddress = null;
        try {
            //服务端,监听端口
            server = new ServerSocket(10000);
            //使用accept进入侦听状态,获取客户端数据
            socket = server.accept();
            //获取输入输出流
            in = socket.getInputStream();
            out = socket.getOutputStream();
            //获取客户端IP,端口
            inetAddress = socket.getInetAddress();
            String ip  = inetAddress.getHostAddress();
            int port = socket.getPort();
            while(true){
                //获取客户端数据
                byte [] by = new byte[1024];
                System.out.println("服务端接收数据:");
                int len = in.read(by);
                String mess = new String(by , 0 , len);
                System.out.println("客户端:" + ip + ":" +port + "告诉了服务器:" + mess );
                //向客户端回话
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                System.out.println("你要告诉客户端:");
                String str = br.readLine();
                out.write(str.getBytes());
                if("bye".equals(mess)){
                    break;
                }
            }
           
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally{
            try {
                //关闭客户端
                socket.close();
                //关闭服务端
                server.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}
效果
客户端启动。。。。。
客户端发送数据。。。
你说:
你好,服务器
你告诉了服务器:
服务端告诉我了:
你好,客户端
客户端发送数据。。。
你说:
bye
你告诉了服务器:
服务端告诉我了:
bye
 
服务器启动:
服务端接收数据:
客户端:127.0.0.1:3722告诉了服务器:你好,服务器
你要告诉客户端:
你好,客户端
服务端接收数据:
客户端:127.0.0.1:3722告诉了服务器:bye
你要告诉客户端:
bye

代码实例3

服务器可以通过客户端的连接,客户端通过键盘录入数据,发送到服务端,服务端接收到数据后,转换成大写在返回给客户端

客户端

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("客户端启动");
        Socket socket = null;
        InputStream in = null;
        OutputStream out = null;
         try {
            socket = new Socket("124.0.0.1",10000);
            in = socket.getInputStream();
            out = socket.getOutputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("请录入:");
            String mess = br.readLine();
            out.write(mess.getBytes());
            System.out.println("=========获得服务器回馈===========");
            byte [] by = new byte[1024];
            int len = in.read(by);
            System.out.println(new String(by , 0 , len));
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally{
            try {
                socket.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

服务端

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("服务器启动:");
        ServerSocket server = null;
        Socket socket = null;
        InputStream in = null;
        OutputStream out = null;
        try {
            //服务器,监听端口
            server = new ServerSocket(10000);
            //使用accept进入监听状态,获取客户端数据
            socket = server.accept();
            //获得输入输出流
            in = socket.getInputStream();
            out = socket.getOutputStream();
            //获得客户端IP,端口
            int port = socket.getPort();
            InetAddress inetAddress = socket.getInetAddress();
            String ip = inetAddress.getHostAddress();
            //取得客户端数据
            byte[] by = new byte[1024];
            int len = in.read(by);
            String mess = new String(by, 0, len);
            //在控制台上输出客户端送来的信息
            System.out.println("该客户端:" + ip + ":" + port + "发送了:" + mess);
            //将其内容转换为大写字母
            String str = mess.toUpperCase();
            //输出到客户端
            out.write(str.getBytes());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally{
            try {
                //关闭服务端
                server.close();
                //关闭客户端
                socket.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }      
        }
    }
}
输入
客户端启动
请录入:
my name is huzhiping
=========获得服务器回馈===========
MY NAME IS HUZHIPING
 
服务器启动:
该客户端:127.0.0.1:2594发送了:my name is huzhiping
多线程服务器

服务器一般是为多个客户端同时服务的,当每个客户端连接到服务端时,可以开一条单独的线程处理这个连接。

服务器

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("服务器启动。。。。");
        ServerSocket server = null;
        Socket socket = null;
        try {
            server = new ServerSocket(10000);
            while (true) {
                socket = server.accept();
                ServerRunnable serverRunnable = new ServerRunnable(socket);
                Thread t1 = new Thread(serverRunnable);
                t1.start();
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
class ServerRunnable implements Runnable {
    Socket socket;
    public ServerRunnable(Socket socket) {
        super();
        this.socket = socket;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        InputStream in = null;
        OutputStream out = null;
        try {
            in = socket.getInputStream();
            out = socket.getOutputStream();
            byte[] by = new byte[1024];
            int len = in.read(by);
            String str = new String(by, 0, len);
            System.out.println("服务器转大写");
            String upperCase = str.toUpperCase();
            out.write(upperCase.getBytes());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally {
            try {
                socket.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}
输出:
服务器启动。。。。
服务器转大写
服务器转大写
服务器转大写
与客户端每次对话都能自动回复,且可进行多线程操作

上传文件

步骤:

1.先启动服务器,再启动客户端。

2.客户端和服务端需要建立连接,服务器向客户端反馈信息。

客户端

1.客户端需要检测文件,文件是否存在,是否是文件。

2.客户端将文件名和文件长度发给服务器,服务器以此判断文件是否存在,文件大小以此验证文件是否上传完毕。

3.客户端根据服务器的反馈信息,如果服务器存在该文件,上传结束,不存在开始上传。

4.客户端开始上传,使用字节输入流,将文件加载到输入流中,读取输入流,通过socket的输出流写到服务器。

服务器:

1.根据客户传送的信息,判断文件是否存在如果存在就不再上传,需要将结果反馈给客户端,。

2.如果不存在,新建字节输出流,将客户端传送的数据,写到服务器中。

3.判断文件的长度和客户端的长度是否一致,一致上传完毕。

客户端

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client2 {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("客户端启动");
        Socket socket = null;
        InputStream in = null;
        OutputStream out = null;
        try {
            //创建客户端
            socket = new Socket("127.0.0.1",10000);
            in = socket.getInputStream();
            out = socket.getOutputStream();
            //获取服务器信息
            byte [] by = new byte[1024];
            int len = in.read(by);
            String mess = new String(by , 0 , len);
            System.out.println(mess);
    //开始上传,准备工作,键盘录入用户路径,并检测文件是否存在,文件是否文件夹
            File file = getFile();
        //获得文件的名称,传递给服务器
            String fileName = file.getName();
            out.write(fileName.getBytes());
            //获取服务器反馈,验证文件是否已经上传
            len = in.read(by);
            String isUpload = new String (by , 0 , len);
                        if("文件存在".equals(isUpload)){
                System.out.println("文件已上传!");
                return ;
            }
            //传递文件长度
            long fileLen = file.length();
            out.write((String.valueOf(fileLen)).getBytes());
            //上传文件
            FileInputStream fis = new FileInputStream(file);
            while((len = fis.read(by)) != -1){
                out.write(by, 0, len);
                out.flush();
                            }
            fis.close();
            //获取服务器上传结果
            len = in.read(by);
            System.out.println(new String(by,0,len));
                                } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            try {
                socket.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    public static File getFile(){
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        while(true){
            String path;
            File file = null;
            try {
                path = br.readLine();
                file = new File(path);
                if(!file.exists()){
                    System.out.println("文件不存在");
                    continue;
                }else if (file.isDirectory()){
                    System.out.println("不支持文件夹上传");
                    continue;
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return file;
        }
    }
}
服务端
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("服务器启动。。。。");
        ServerSocket server = null;
        Socket socket = null;
        InputStream in = null;
        OutputStream out = null;
            try {
                //创建服务端
                server = new ServerSocket(10000);
                //获得客户端
                socket = server.accept();
                in = socket.getInputStream();
                out = socket.getOutputStream();
                //向客户端反馈信息,表示连接成功
                out.write("连接成功,请输入上传文件路径:".getBytes());
               
                //获得客户端上传文件的名字
                byte [] by = new byte[1024];
                int len = in.read(by);
                String fileName = new String(by,0,len);
                //创建服务器目录保存文件
                File dir = new File("c:\\upload");
                dir.mkdir();
                File file = new File(dir,fileName);
                //服务器检测文件是否存在
                if(file.exists()){
                    out.write("文件存在".getBytes());
                    return ;
                }else{
                    out.write("文件不存在".getBytes());
                }
                    //获取本地文件的长度,结缘判断,是否成功上传
                len = in.read(by);
                String strLen = new String(by , 0 , len);
                long fileLen = Long.parseLong(strLen);
                String ip = socket.getInetAddress().getHostAddress();
                int port = socket.getPort();
                System.out.println(ip + ":" + port + "开始上传文件:" + file.getName());
                //接收文件
                FileOutputStream fos = new FileOutputStream(file);
                //读到文件的末尾,客户湍没有关闭,读不到-1
                while((len = in.read(by))!= -1){
                    fos.write(by , 0 , len);
                    fos.flush();
                    if(file.length() == fileLen){
                        break;
                    }
                }
                fos.close();
                //向客户端反馈结果
                out.write("文件上传完毕!!".getBytes());
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }finally{
                try {
                    socket.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
    }
}
输出
客户端启动
连接成功,请输入上传文件路径:
a.rmvb
文件不存在
c:\\a.rmvb
文件上传完毕!!
服务器启动。。。。
127.0.0.1:3251开始上传文件:a.rmvb

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值