网络编程系列之入门篇(Java)

来源:互联网 发布:韩国主播用什么软件 编辑:程序博客网 时间:2024/06/05 08:42

网络编程基础


      • 网络编程基础
        • 学习网络编程的原因
        • 网络通讯的三要素
          • IP地址
          • 端口
          • 协议
        • Java中Socket编程
          • UDP下Socket通信
            • UDP协议中Socket编程步骤总结
            • UDP协议注意事项
            • 出现数据包丢失的情况
          • TCP下Socket通信
            • TCP协议中Socket编程步骤总结
            • TCP协议编程示例
        • 山寨Tomcat服务器


学习网络编程的原因


网络编程主要是实现计算机与计算机之间的数据传输问题,网络编程要与网页编程概念区分开来,Java一般不用来做桌面应用软件,PC机基本不用网络编程,但是如果以后要学习的是安卓方向,那么就会用到网络编程知识。那么为什么又要学习网络编程呢?因为在Java SE的小项目中,设计到网络编程、GUI编程的等都集合在一起的项目才是练手的最好项目,所以我觉得还是要好好学习网络编程。在网络编程中应该学习的内容是:分布在不同地域的计算机通过外部设备实现消息、数据、资源共享。

网络通讯的三要素


  • IP 
    地址 
    • 找到通讯双方计算机的方式
  • 端口 
    • 找到双方通信软件的方式,不同的软件通过不同的端口对相应的软件进行监控
  • 协议 
    • 计算机与计算机之间通讯需要外界设备,比如路由器,协议规定了路由双方必须采用相同的协议进行解析,否则根本不能正确的发送消息。协议用来规范通信双方发送的数据帧以及编码解码的规定。
IP地址

IP地址的本质就是一个由32位的二进制数组成的数据,但是为了便于人们读取,将其中的8位作为一个单元,切分成了4份,就形成了现在的方式,比如:192.168.101.44等,每一个切分后的块可表示的范围是0-255。

IP地址等于网络号+主机号构成,其中子网掩码中未255的部分全部都为网络号,IP地址可以分为三类:

  • A类地址: 一个网络号+三个主机号 2^24次方台机器 政府机关在用
  • B类地址: 两个网络号+两个主机号 2^16次方台机器 学校、银行等在用
  • C类地址 三个网络号+一个主机号 2^8次方台几区 私人使用 
    • 我们平常使用的IP是从路由器过滤出来的。

在Java中使用使用了一个类来描述IP地址。在java.NET.InetAddress类中,可以用来描述一个IP地址,下面的代码说明了该类的基本用法。

package com.jpzhutech.inetaddress;import java.net.InetAddress;import java.net.UnknownHostException;public class TestInetAddress {    public static void main(String[] args) {        InetAddress inetAddress = null;        try {            // 获取本机的信息            inetAddress = InetAddress.getLocalHost();  //得到本机的IP地址,如果没装网卡就没有IP地址            String hostName = inetAddress.getHostName();            //System.out.println(hostName); //显示本机的主机名            String hostAddress = inetAddress.getHostAddress();            System.out.println(hostAddress);   //显示本机的ip地址            /*获取别人的ip地址            InetAddress byName = InetAddress.getByName("DESKTOP-G56LBO2"); //根据ip或者主机名就能得到相应的主机信息            String hostName = byName.getHostName();            System.out.println(hostName);            */            /* 根据域名得到ip地址的数组,这种情况也常会发生            InetAddress[] allByName = InetAddress.getAllByName("www.baidu.com"); //为什么该方法会返回一个数组呢?String host可以写域名也可以写ip还可以写主机名,baidu的一个域名就注册了两个ip地址            for(int i = 0 ; i < allByName.length;i++){                InetAddress inetAddress2 = allByName[i];                String hostAddress = inetAddress2.getHostAddress();                System.out.println(hostAddress);                String hostName = inetAddress2.getHostName();                System.out.println(hostName);            }            */        } catch (UnknownHostException e) {            throw new RuntimeException(e);        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
端口

端口在Java中并没有使用类来描述,因为端口号仅仅是一个标识符,端口号从0-65535的范围,其它的无效,但是我们都能用0-65535吗?回答是不能,0-1023系统绑定了一些服务,不能用,如果用会报错。1024-49151系统绑定了一些松散的服务,松散的含义是有一些端口可能没被占用,有些被占用了,也可以使用这里的端口,如果发生冲突换一个端口就好了。1024-65535我们可以使用,如果发生冲突就换一个其他的端口号。49152-65535动态或者私有的端口,我们可以随便用,在使用之前使用cports查看你想使用的端口是否有端口占用。

协议

  • UDP通讯协议 
    • 将数据封装成为数据包,不需要建立连接。
    • 每个包的大小限制在64K中。
    • 因为无连接所以不可靠,不可靠指的是可能发生数据包的丢失
    • 因为不需要建立连接,所有速度快
    • User Datagram Protocol的简写
    • UDP通信是不分客户端和服务端的,只分接收端和发送端
    • 例如:对讲机、游戏…
  • TCP通讯协议 
    • 面向连接,有特有的通道
    • 在连接中传输大数据量
    • 通过三次握手机制建立连接,可靠协议
    • 通信前必须建立连接,效率稍低
    • 如:打电话、文件的传输

Java中Socket编程


在Java中网络通信业被称为Socket通信,Socket翻译为:套接字。我们可以理解为“插座”,在通信之前需要安装插座,之后建立管道进行通信。

UDP下Socket通信

  • DatagramSocket(UDP插座服务) 
    • 接收端与发送端都要启动DatagramSocket服务
    • 既有接收数据的服务,也有发送数据的服务
  • DatagramPacket(数据包类) 
    • 双方在传输数据时要初始化该包的实例

TestUdpSender.java

package com.jpzhutech.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 TestUdpSender {    public static void main(String[] args) {        //建立UDP服务,很像码头运送货物的场景,在建立UDP时不需要指定端口等信息,这些信息应该被封装在数据包中        DatagramSocket datagramSocket = null;         DatagramPacket datagramPacket = null;        try {             datagramSocket = new DatagramSocket();             //准备数据,将数据封装到数据包中             String data = "这是我第一个UDP服务的例子";             try {                 datagramPacket = new DatagramPacket(data.getBytes(), data.getBytes().length, InetAddress.getLocalHost(), 9090);//第三个参数指的是发送的IP地址,最后一个参数是端口号                 //调用UDP的服务发送数据包                 try {                    datagramSocket.send(datagramPacket);                } catch (IOException e) {                    throw new RuntimeException(e);                }             } catch (UnknownHostException e) {                throw new RuntimeException(e);            }        } catch (SocketException e) {            throw new RuntimeException(e);        }finally{            //关闭资源实际上就是释放端口等资源            if(datagramSocket != null){                datagramSocket.close();            }        }    }    public void sender(){    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

TestUdpReceive.java

package com.jpzhutech.udp;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.SocketException;public class TestUdpReceive {    public static void main(String[] args) {        DatagramSocket datagramSocket = null;        DatagramPacket datagramPacket = null;        try {            //建立UDP服务,接收端必须套时时刻刻监听着发送端的端口,因为发送端根本不管接收端是否准备好,直接发送数据             datagramSocket = new DatagramSocket(9090);            //建立一个数据包的对象,发送端发来的数据会被放在该buf数组中             byte[] buf = new byte[1024];             datagramPacket = new DatagramPacket(buf, buf.length);             //调用UDP服务接收数据             try {                datagramSocket.receive(datagramPacket); //阻塞式操作,如果没有接收到数据,就一直等待                System.out.println("接收到的数据为:"+new String(buf,0,datagramPacket.getLength())); //第三个参数获取的是实际存储的字节数据的大小            } catch (IOException e) {                throw new RuntimeException(e);            }        } catch (SocketException e) {            throw new RuntimeException(e);        }finally{            if (datagramSocket != null) {                datagramSocket.close();            }        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

如果将上述接收端的缓冲数组大小换成5而不是1024,那么很显然不能完全的读取到数据,就会出错,怎么避免这个问题?无解:这是由UDP协议本身决定的。

UDP协议中Socket编程步骤总结

  • 发送端 
    • 建立UDP服务
    • 准备数据,把数据封装到数据包中进行发送,发送端的数据包要带上ip地址与端口号。
    • 调用UDP的send发送数据
    • 关闭UDP服务
  • 接收端 
    • 建立UDP服务
    • 准备空的数据包接收数据,只需要知道端口号就行
    • 调用UDP的服务接收数据,使用receive()方法
    • 关闭UDP服务
UDP协议注意事项

在使用UDP协议进行网络通讯时,必须要注意:

  • 对方的IP地址 
    • 单个人发送:指定其具体的ip地址
    • 广播地址:广播地址就是主机号为255的地址,给广播IP地址发送消息的时候,在同一个网络段的机器都能接收到信息,只有在UDP协议中才有广播地址发送这个说法
  • 服务的端口号
  • 数据包的格式

上述三个条件缺一不可,比如如果你的数据包的格式不对,接收端会拒绝你的数据,接收方会判定为你现在的数据为非法的数据,所以接收不到。每一个网络程序都有自己所处理的特定格式的数据,如果接收到数据不符合指定的格式,就会被当做垃圾数据丢弃(相当于加密),这么做是为了保证安全。

通常定义的数据格式: 
version: time: sender: ip: flag(发送的标识符): content(真正要发送的内容)。

出现数据包丢失的情况

什么情况下会出现数据丢失的情况呢?

  • 带宽不足的情况 
    • 局域网基本不存在带宽不足的情况
  • CPU处理能力不足
TCP下Socket通信

TCP通信特点:

  • TCP协议是基于IO流进行数据传输的,是面向连接的。
  • TCP进行数据传输时数据没有大小限制。
  • TCP面向连接,通过三次握手保证数据的完整性,是一个可靠的协议。
  • TCP是面向连接的,所以速度慢。
  • TCP是严格的区分客户端与服务器端。
  • 比如:打电话、文件传输使用TCP协议、下载等。

  • Socket(客户端)

  • ServerSocket(服务器端)

TcpClient.java

package com.jpzhutech.tcp;/** * 端口被占用的异常可能会经常出现,这都是由于已经有程序在运行 * @author 朱君鹏 * */import java.io.IOException;import java.io.OutputStream;import java.net.InetAddress;import java.net.Socket;import java.net.UnknownHostException;public class TcpClient {    public static void main(String[] args) {        Socket socket = null;        try {            // 建立TCP服务            socket = new Socket(InetAddress.getLocalHost(), 9090);            // 获取socket对象的输出流对象            OutputStream outputStream = socket.getOutputStream();            // 利用输出流对象把数据写出即可            outputStream.write("服务端你好".getBytes());        } catch (UnknownHostException e) {            throw new RuntimeException(e);        } catch (IOException e) {            throw new RuntimeException(e);        } finally {            if (socket != null) {                try {                    socket.close();                } catch (IOException e) {                    throw new RuntimeException(e);                }            }        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

TcpServer.java

package com.jpzhutech.tcp;import java.io.IOException;import java.io.InputStream;import java.net.ServerSocket;public class TcpServer {    public static void main(String[] args) {        ServerSocket serverSocket = null;        try {            //建立服务器端TCP连接            serverSocket = new ServerSocket(9090);            //建立输入流对象,其中accept方法也是阻塞型的方法,用于接收客户端的连接,如果没有客户端与其进行连接时,会一直等            InputStream inputStream = serverSocket.accept().getInputStream();//想要使用InputStream,但是只有Socket才有,只能使用accept方法获取            byte[] buf = new byte[1024];            int length = 0 ;            while((length = inputStream.read(buf)) != -1 ){                System.out.println("接收到的数据为:"+new String(buf,0,length));            }        } catch (IOException e) {            throw new RuntimeException(e);        } finally {            if (serverSocket != null) {                try {                    serverSocket.close();                } catch (IOException e) {                    throw new RuntimeException(e);                }            }        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
TCP协议中Socket编程步骤总结

  • 建立TCP服务
  • 接收客户端的连接产生Socket
  • 获取对应的流对象,读取后写出数据
  • 关闭资源
TCP协议编程示例

TcpClient.java

package com.jpzhutech.tcp;/** * 端口被占用的异常可能会经常出现,这都是由于已经有程序在运行 * @author 朱君鹏 * */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 TcpClient {    public static void main(String[] args) {        Socket socket = null;        try {            // 建立TCP服务            socket = new Socket(InetAddress.getLocalHost(),9090);            // 获取socket对象的输出流对象            OutputStream outputStream = socket.getOutputStream();            // 利用输出流对象把数据写出即可            outputStream.write("服务端你好".getBytes());            outputStream.flush();            socket.shutdownOutput(); //关闭输出流,如果想知道为什么,注释该语句会看到其中的原因,参见文章:http://wiki.jikexueyuan.com/project/java-socket/socket-read-deadlock.html            //获取输入流对象,读取服务端回送的数据            InputStream inputStream = socket.getInputStream();            byte[] buf = new byte[1024];            int length = 0 ;            while((length = inputStream.read(buf)) != -1 ){   //该行指令实际上没有执行                System.out.println("客户端接收到的数据:"+ new String(buf, 0, length) );            }        } catch (UnknownHostException e) {            throw new RuntimeException(e);        } catch (Exception e) {            throw new RuntimeException(e);        } finally {            if (socket != null) {                try {                    socket.close();                } catch (IOException e) {                    throw new RuntimeException(e);                }            }        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

TcpServer.java

package com.jpzhutech.tcp;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.ServerSocket;import java.net.Socket;public class TcpServer {    public static void main(String[] args) {        ServerSocket serverSocket = null;        try {            //建立服务器端TCP连接            serverSocket = new ServerSocket(9090);            //建立输入流对象,其中accept方法也是阻塞型的方法,用于接收客户端的连接,如果没有客户端与其进行连接时,会一直等            Socket socket = serverSocket.accept();  //拿到与服务器端建立连接的客户端            InputStream inputStream = socket.getInputStream();//想要使用InputStream,但是只有Socket才有,只能使用accept方法获取            byte[] buf = new byte[1024];            int length = 0 ;            int count = 0 ;            while((length = inputStream.read(buf)) != -1 ){                  System.out.println("服务器端接收到的数据为:"+new String(buf,0,length));            }            //拿到输出流对象,输出数据            OutputStream outputStream = socket.getOutputStream();            String string = "客户端你也好啊!";            outputStream.write(string.getBytes());            outputStream.flush();            String string2 = "你找我干嘛?";            System.out.println(string2);            socket.shutdownOutput(); //关闭输出流,如果想知道为什么,注释该语句会看到其中的原因,只有有了该语句,在客户端的read(buf)方法中才会在最后返回-1,程序才能结束,否则会造成死锁        } catch (IOException e) {            throw new RuntimeException(e);        } finally {            if (serverSocket != null) {                try {                    serverSocket.close();                } catch (IOException e) {                    throw new RuntimeException(e);                }            }        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

将上述的代码改造,得到可以产生类似QQ中问答效果的代码。

ChatClient.java

package com.jpzhutech.tcpqq;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.net.InetAddress;import java.net.Socket;public class ChatClient {    public static void main(String[] args) {        Socket socket = null;        try {             socket = new Socket(InetAddress.getLocalHost(), 9090);             OutputStream outputStream = socket.getOutputStream(); //获取字节流             OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream); //将字节流转化为字符流             //获取键盘的输入流对象             BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));  //将键盘的字节流输入转换为字符流             String line = null;             InputStream inputStream = socket.getInputStream();             BufferedReader bufferedReader2 = new BufferedReader(new InputStreamReader(inputStream));             //不断读取键盘的数据,然后输出             while((line = bufferedReader.readLine()) != null){                 outputStreamWriter.write(line+"\r\n");                 //刷新                 outputStreamWriter.flush();                 //读取服务端回送的数据                 line = bufferedReader2.readLine();                 System.out.println("服务端回送的数据是:" + line);             }        } catch (IOException e) {            throw new RuntimeException(e);        }finally{            if(socket != null){                try {                    socket.close();                } catch (IOException e) {                    throw new RuntimeException(e);                }            }        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

ChatServer.java

package com.jpzhutech.tcpqq;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.net.ServerSocket;import java.net.Socket;public class ChatServer {    public static void main(String[] args) {        ServerSocket serverSocket = null;        try {             serverSocket = new ServerSocket(9090);             //产生socket             Socket socket = serverSocket.accept();             //获取socket的输入流对象             InputStream inputStream = socket.getInputStream();  //得到字节流             InputStreamReader inputStreamReader = new InputStreamReader(inputStream);             BufferedReader bufferedReader = new BufferedReader(inputStreamReader);             String line = null;            // 获取socket的输出流            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(                    socket.getOutputStream());            // 获取键盘的输入流对象            BufferedReader bufferedReader1 = new BufferedReader(                    new InputStreamReader(System.in));             while((line = bufferedReader.readLine()) != null){                 System.out.println("服务器接收到的数据:"+line);                 System.out.println("请输入回送给客户端的数据");                 line = bufferedReader1.readLine();                 outputStreamWriter.write(line+"\r\n");                 outputStreamWriter.flush();             }        } catch (IOException e) {            throw new RuntimeException(e);        }finally{            if(serverSocket != null){                try {                    serverSocket.close();                } catch (IOException e) {                    throw new RuntimeException(e);                }            }        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

山寨Tomcat服务器


对上述ChatClient.java和ChatServer.java代码的思考,Tomcat服务器实际上的原来和该代码的原理类似,客户端给服务器发一个请求,服务器端会对相应的请求进行处理,上面的代码实现的是客户端说一句话,服务器端会对你说出的话进行响应,很相似,我们可以针对上述代码进行改造,实现一个山寨的Tomcat服务器。实际上浏览器与服务器之间的通讯就是使用了TCP协议。浏览器就是客户端,有兴趣的朋友可以自己实现。

0 0
原创粉丝点击