Java Socket应用---慕课网笔记

来源:互联网 发布:我的世界0.14作弊js 编辑:程序博客网 时间:2024/06/08 19:52
第一章 网络基础知识
1-1 网络基础简介

Java最初是作为网络编程语言出现的,其对网络提供了高度的支持
而在网络编程中使用最多的就是Socket,像QQ,MSN都使用了Socket
相关的技术

Java提供了强大的类,方便网络编程的开发

Socket编程
1. 网络基础知识
2. InetAddress类
3. URL
4. TCP编程
5. UDP编程

两台计算机通过网络进行通信的必备条件:
- IP地址
- 协议
- 端口号

TCP/IP协议
TCP/IP是目前世界上应用最为广泛的协议
是以TCP和IP为基础的不同层次上多个协议的集合
也称:TCP/IP协议族 或 TCP/IP协议栈
- TCP:Transmission Control Protocol 传输控制协议
- IP:Internet Protocol 互联网协议

TCP/IP模型
5. 应用层
- HTTP超文件传输协议
- FTP文件传输协议
- SMTP简单邮件传输协议
- Telnet远程登录服务
4. 传输层
- TCP/IP协议
3. 网络层
2. 数据链路层
1. 物理层
- 网线
- 双绞线
- 网卡

IP地址
为实现网路中不同计算机之间的通信,每台机器都必须有一个唯一的
标识–IP地址

IP地址格式:数字型,如:192.168.0.1
IPv4定义了32位2进制的格式

端口
- 用于区分不同应用程序
- 端口号范围0~65535,其中0~1023为系统所保留
- IP地址和端口号组成了所谓的Socket,Socket是网络上运行
的程序之间双向通信链路的终结点,是TCP和UDP的基础。
- http:80 ftp:21 telnet:23

Java中的网络支持
针对网络通信的不同层次,Java提供的网络功能有四大类:
1. InetAddress:用于标识网络上的硬件资源。
2. URL:统一资源定位符 通过URL可直接读取或写入网络上的数据。
3. Sockets:使用TCP协议实现网络通信的Socket相关类。
4. Datagram:使用UDP协议,将数据保存在数据报中,通
过网络进行通信。

第2章 Java 中网络相关 API 的应用
2-1 Java 中的 InetAddress 的应用

InetAddress类
1. InetAddress类用于标识网络上的硬件资源,表示互联
网协议(IP)地址。

JDK1.8
Class InetAddress
java.lang.Object
java.net.InetAddress

这个类代表一个互联网协议(IP)地址。

Modifier and Type Method and Description boolean equals(Object obj)
将此对象与指定的对象进行比较。 byte[] getAddress()
返回该对象的 InetAddress原IP地址。 static InetAddress[] getAllByName(String host)
给定一个主机的名称,返回其IP地址的数组,基于系统上的配置的名称服务。 static InetAddress getByAddress(byte[] addr)
返回给定的原始IP地址 InetAddress对象。 static InetAddress getByAddress(String host, byte[] addr)
它创造了一个基于所提供的主机名和IP地址。 static InetAddress getByName(String host)
确定主机的IP地址,给定主机名。 String getCanonicalHostName()
获取此IP地址的完全限定的域名。 String getHostAddress()
返回文本表示中的IP地址字符串。 String getHostName()
获取此IP地址的主机名。 static InetAddress getLocalHost()
返回本地主机的地址。 static InetAddress getLoopbackAddress()
返回回送地址。 int hashCode()
返回该IP地址的hash码。 boolean isAnyLocalAddress()
实用程序来检查是否一个通配符解决它。 boolean isLinkLocalAddress()
实用程序检查,如果它是一个链路本地地址。 boolean isLoopbackAddress()
实用程序来检查它是环回地址。 boolean isMCGlobal()
实用程序,检查多播地址是否具有全局范围。 boolean isMCLinkLocal()
实用程序,检查多播地址是否有连接范围。 boolean isMCNodeLocal()
实用程序,检查多播地址是否有节点范围。 boolean isMCOrgLocal()
实用程序,检查多播地址是否有组织范围。 boolean isMCSiteLocal()
实用程序,检查多播地址是否有网站范围。 boolean isMulticastAddress()
实用程序检查,如果它是一个IP多播地址。 boolean isReachable(int timeout)
测试是否该地址是可到达的。 boolean isReachable(NetworkInterface netif, int ttl, int timeout)
测试是否该地址是可到达的。 boolean isSiteLocalAddress()
实用程序检查,如果它是一个站点本地地址。 String toString()
将这个IP地址到一个 String。
/* * InetAddress类 */public class Test01 {    public static void main(String[] args) throws UnknownHostException {        // 获取本机的InetAddress实例        InetAddress address = InetAddress.getLocalHost();        System.out.println("计算名:" + address.getHostName());        System.out.println("IP地址:" + address.getHostAddress());        byte[] bytes = address.getAddress();// 获取字节数组形式的IP地址        System.out.println("字节数组形式的IP:" + Arrays.toString(bytes));        System.out.println(address);// 直接输出InetAddress对象        // 根据机器名获取InetAddress实例        InetAddress address2 = InetAddress.getByName("Sc-201411281008");        System.out.println("计算名:" + address2.getHostName());        System.out.println("IP地址:" + address2.getHostAddress());    }}
2-2 Java 中的 URL 的应用

URL
1. URL(Uniform Resource Locator)统一资源定位符,表示Internet上某一资源的地址。
2. URL由两部分组成:协议名称和资源名称,中间用冒号隔开。
- http://www.imooc.com
- 协议名称:http
- 资源名称:www.imooc.com
3. 在java.net包中,提供了URL类来表示URL。

Class URL
java.lang.Object
java.net.URL

类 URL代表统一资源定位符,指向“万维网上的资源”。一个资源可以是简单的作为一个文件或一个目录,或者它可以是一个更复杂的对象的参考,如查询到数据库或搜索引擎。

构造方法 Constructor and Description URL(String spec) 创建于 String表示 URL对象。 URL(String protocol, String host, int port, String file) 创建从指定的 protocol, host,一 URL对象 port数,和 file。 URL(String protocol, String host, int port, String file, URLStreamHandler handler) 创建从指定的 protocol, host, port数, file一 URL对象,和 handler。 URL(String protocol, String host, String file) 创建一个URL指定的 protocol名字, host名字,和 file名称。 URL(URL context, String spec) 通过在指定的上下文中解析给定的规范,创建一个网址。 URL(URL context, String spec, URLStreamHandler handler) 通过在指定的上下文中解析给定的规范与指定的处理程序创建一个链接。 Modifier and Type Method and Description boolean equals(Object obj)
将此网址与另一个对象进行比较。 String getAuthority()
得到这 URL权威部分。 Object getContent()
获取此网址的内容。 Object getContent(类[] classes)
获取此网址的内容。 int getDefaultPort()
得到这个 URL相关协议的默认端口号。 String getFile()
得到这 URL文件名。 String getHost()
得到这 URL主机名称,如适用。 String getPath()
得到这 URL路径的一部分。 int getPort()
得到这 URL端口号。 String getProtocol()
得到这 URL协议名称。 String getQuery()
得到这 URL查询的一部分。 String getRef()
得到锚(也被称为“参考”)这 URL。 String getUserInfo()
得到这 URL用户信息部分。 int hashCode()
创建一个适用于哈希表索引的整数。 URLConnection openConnection()
返回一个 URLConnection实例表示的远程对象的连接被称为 URL。 URLConnection openConnection(Proxy proxy)
同 openConnection(),除了连接将通过指定的代理进行;协议处理程序不支持proxing将忽略代理参数,使正常的连接。 InputStream openStream()
打开一个连接到这 URL和返回的连接阅读 InputStream。 boolean sameFile(URL other)
比较两个网址,不包括片段组件。 static void setURLStreamHandlerFactory(URLStreamHandlerFactory fac)
设置应用程序的 URLStreamHandlerFactory。 String toExternalForm()
构建该 URL字符串表示形式。 String toString()
构建该 URL字符串表示形式。 URI toURI()
返回一个 URI相当于这个URL。
/* * URL常用方法 */public class Test02 {    public static void main(String[] args) {        try {            //创建一个URL实例            URL imooc=new URL("http://www.imooc.com");            //?后面表示参数,#后面表示锚点            URL url=new URL(imooc, "/index.html?username=tom#test");            System.out.println("协议:"+url.getProtocol());            System.out.println("主机:"+url.getHost());            //如果未指定端口号,则使用默认的端口号,此时getPort()方法返回值为-1            System.out.println("端口:"+url.getPort());            System.out.println("文件路径:"+url.getPath());            System.out.println("文件名:"+url.getFile());            System.out.println("相对路径:"+url.getRef());            System.out.println("查询字符串:"+url.getQuery());        } catch (MalformedURLException e) {            e.printStackTrace();        }    }}

使用URL读取网页内容
1. 通过URL对象的openStream()方法可以得到指定资源的
输入流。
2. 通过输入流可以读取、访问网络上的数据。

/* * 使用URL读取网页内容 */public class Test03 {    public static void main(String[] args) {        try {            //创建一个URL实例            URL url = new URL("http://www.baidu.com");            //通过URL的openStream方法获取URL对象所表示的资源的字节输入流            InputStream is = url.openStream();            //将字节输入流转换为字符输入流            InputStreamReader isr = new InputStreamReader(is, "utf-8");            //为字符输入流添加缓冲            BufferedReader br = new BufferedReader(isr);            String data = br.readLine();//读取数据            while (data != null) {//循环读取数据                System.out.println(data);//输出数据                data = br.readLine();            }            br.close();            isr.close();            is.close();        } catch (MalformedURLException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }    }}
第3章 通过 Socket 实现 TCP 编程
3-1 Socket 简介

Socket通信
TCP协议是面向连接、可靠的、有序的,以字节流的方式发送数据
基于TCP协议实现的网络通信的类
- 客户端的Socket类
- 服务端的ServerSocket类

Socket通信模型
1. 建立连接
- Server
- 建立服务端侦听socket
- 等待并接收连接请求
- 接收请求后创建socket
- Client
- 创建连接socket向服务端发送请求
2. 开始通信
- Server
- InputStream
- OutputStream
- Client
- OutputStream
- InputStream
3. 结束通信
- Server
- 关闭socket及相关资源
- Client
- 关闭socket及相关资源

Socket通信实现步骤
1. 创建ServerSocket和Socket
2. 打开连接到Socket的输入/输出流
3. 按照协议对Socket进行读/写操作
4. 关闭输入输出流、关闭Socket

Class ServerSocket

java.lang.Object
java.net.ServerSocket

这个类实现了服务器套接字。服务器套接字等待来自网络的请求。它基于该请求执行某些操作,然后可能向请求者返回结果。

构造方法 Constructor and Description ServerSocket() 创建一个绑定服务器套接字。 ServerSocket(int port) 创建一个服务器套接字,绑定到指定的端口。 ServerSocket(int port, int backlog) 创建一个服务器套接字,并将其绑定到指定的本地端口号,并使用指定的积压。 ServerSocket(int port, int backlog, InetAddress bindAddr) 用指定的端口创建一个服务器,听积压,和本地IP地址绑定到。 Modifier and Type Method and Description Socket accept()
监听要对这个套接字作出的连接并接受它。 void bind(SocketAddress endpoint)
ServerSocket绑定到一个特定的地址(IP地址和端口号)。 void bind(SocketAddress endpoint, int backlog)
ServerSocket绑定到一个特定的地址(IP地址和端口号)。 void close()
关闭这个套接字。 ServerSocketChannel getChannel()
返回与此套接字关联的独特的 ServerSocketChannel对象,如果任何。 InetAddress getInetAddress()
返回此服务器套接字的本地地址。 int getLocalPort()
返回此套接字正在侦听的端口号。 SocketAddress getLocalSocketAddress()
返回此套接字绑定到的端点的地址。 int getReceiveBufferSize()
得到这个 ServerSocket的 SO_RCVBUF期权的价值,即该缓冲区的大小,将用于接受来自这 ServerSocket插座。 boolean getReuseAddress()
如果 SO_REUSEADDR启用。 int getSoTimeout()
检索设置 SO_TIMEOUT。 protected void implAccept(Socket s)
子类使用此方法重载ServerSocket()返回自己的子类的插座。 boolean isBound()
返回的ServerSocket绑定状态。 boolean isClosed()
返回的ServerSocket关闭状态。 void setPerformancePreferences(int connectionTime, int latency, int bandwidth)
设置此ServerSocket性能偏好。 void setReceiveBufferSize(int size)
设置一个默认值为提出接受这 ServerSocket插座 SO_RCVBUF选项。 void setReuseAddress(boolean on)
启用/禁用 SO_REUSEADDR套接字选项。 static void setSocketFactory(SocketImplFactory fac)
设置服务器套接字实现工厂为应用程序。 void setSoTimeout(int timeout)
启用/禁用 SO_TIMEOUT以指定的超时时间,以毫秒为单位。 String toString()
返回此套接字作为 String实现的地址与端口。

Class Socket
java.lang.Object
java.net.Socket

这个类实现了客户端套接字(也被称为“套接字”)。套接字是两台机器之间的通信的一个端点。

构造方法 Constructor and Description Socket() 创建一个连接的套接字,与socketimpl系统默认的类型。 Socket(InetAddress address, int port) 创建一个流套接字,并将其与指定的IP地址中的指定端口号连接起来。 Socket(InetAddress host, int port, boolean stream) 过时的。 使用UDP传输DatagramSocket。 Socket(InetAddress address, int port, InetAddress localAddr, int localPort) 创建一个套接字,并将其与指定的远程端口上的指定的远程地址连接起来。 Socket(Proxy proxy) 创建一个连接的套接字类型,指定代理,如果有,应该使用无论任何其他设置。 Socket(SocketImpl impl) 创建一个用户指定的socketimpl连接插座。 Socket(String host, int port) 创建一个流套接字,并将其与指定的主机上的指定端口号连接起来。 Socket(String host, int port, boolean stream) 过时的。 使用UDP传输DatagramSocket。 Socket(String host, int port, InetAddress localAddr, int localPort) 创建一个套接字,并将其连接到指定的远程端口上的指定的远程主机上。 Modifier and Type Method and Description void bind(SocketAddress bindpoint)
将套接字绑定到本地地址。 void close()
关闭这个套接字。 void connect(SocketAddress endpoint)
将此套接字连接到服务器。 void connect(SocketAddress endpoint, int timeout)
将此套接字与指定的超时值连接到服务器。 SocketChannel getChannel()
返回与此套接字关联的独特的 SocketChannel对象,如果任何。 InetAddress getInetAddress()
返回套接字连接的地址。 InputStream getInputStream()
返回此套接字的输入流。 boolean getKeepAlive()
如果 SO_KEEPALIVE启用。 InetAddress getLocalAddress()
获取绑定的套接字的本地地址。 int getLocalPort()
返回此套接字绑定的本地端口号。 SocketAddress getLocalSocketAddress()
返回此套接字绑定到的端点的地址。 boolean getOOBInline()
如果 SO_OOBINLINE启用。 OutputStream getOutputStream()
返回此套接字的输出流。 int getPort()
返回此套接字连接的远程端口号。 int getReceiveBufferSize()
得到这个 Socket的 SO_RCVBUF选项的值,是由平台用于该 Socket输入缓冲区的大小。 SocketAddress getRemoteSocketAddress()
返回此套接字连接的端点的地址,或如果它是无关的 null。 boolean getReuseAddress()
如果 SO_REUSEADDR启用。 int getSendBufferSize()
得到这个 Socket的 SO_SNDBUF期权价值,即缓冲区的大小由平台用于输出在这 Socket。 int getSoLinger()
返回设置 SO_LINGER。 int getSoTimeout()
返回设置 SO_TIMEOUT。 boolean getTcpNoDelay()
如果 TCP_NODELAY启用。 int getTrafficClass()
获取从这个套接字发送的数据包的IP头中的业务类或服务类型 boolean isBound()
返回套接字的绑定状态。 boolean isClosed()
返回套接字的关闭状态。 boolean isConnected()
返回套接字的连接状态。 boolean isInputShutdown()
返回套接字连接的读半是否关闭。 boolean isOutputShutdown()
返回套接字连接的写是否关闭的是否关闭。 void sendUrgentData(int data)
在套接字上发送一个字节的紧急数据。 void setKeepAlive(boolean on)
启用/禁用 SO_KEEPALIVE。 void setOOBInline(boolean on)
启用/禁用 SO_OOBINLINE(TCP紧急数据收据)默认情况下,此选项是禁用TCP套接字上接收紧急数据是默默丢弃。 void setPerformancePreferences(int connectionTime, int latency, int bandwidth)
设置此套接字的性能首选项。 void setReceiveBufferSize(int size)
集 SO_RCVBUF选项,这 Socket指定值。 void setReuseAddress(boolean on)
启用/禁用 SO_REUSEADDR套接字选项。 void setSendBufferSize(int size)
设置这个 Socket指定值的 SO_SNDBUF选项。 static void setSocketImplFactory(SocketImplFactory fac)
设置客户端套接字实现工厂的应用程序。 void setSoLinger(boolean on, int linger)
启用/禁用 SO_LINGER与指定的逗留的时间秒。 void setSoTimeout(int timeout)
启用/禁用 SO_TIMEOUT以指定的超时时间,以毫秒为单位。 void setTcpNoDelay(boolean on)
启用/禁用 TCP_NODELAY(禁用/启用Nagle的算法)。 void setTrafficClass(int tc)
集交通类或从该套接字发送数据包的IP报头字节型服务。 void shutdownInput()
将此套接字的输入流放在“流结束”中。 void shutdownOutput()
禁用此套接字的输出流。 String toString()
将这一 String插座。
3-2 编程实现基于 TCP 的 Socket 通信之服务器端
  • 服务器端

    1. 创建ServerSocket对象,绑定监听端口
    2. 通过accept()方法监听客户端请求
    3. 连接建立后,通过输入流读取客户端发送的请求信息
    4. 通过输出流向客户端发送请求
    5. 关闭相关资源
  • 客户端

    1. 创建Socket对象,指明需要连接的服务器的地址和端口号
    2. 连接建立后,通过输出流向服务器端发送请求信息
    3. 通过输入流获取服务器响应的信息
    4. 关闭相关资源
/** * 基于TCP协议的socket通信,实现用户登录 * 服务器端 */public class Server {    public static void main(String[] args) {        try {            //1.创建一个服务器端Socket,即ServerSocket,指定绑定的端口            ServerSocket serverSocket = new ServerSocket(8888);            //2.调用accept()方法开始监听,等待客户端 的连接            System.out.println("***服务器即将启动,等待客户端的连接***");            Socket socket = serverSocket.accept();            //3.获取输入流,并读取客户端信息            InputStream is = socket.getInputStream();//字节输入流            InputStreamReader isr = new InputStreamReader(is);//将字节输入流转换为字符流            BufferedReader br = new BufferedReader(isr);//为输入流添加缓冲            String info = null;            while((info=br.readLine())!=null) {//循环读取客户端的信息                System.out.println("我是服务器,客户端说:"+info);            }            socket.shutdownInput();//关闭输入流            //4.关闭资源            br.close();            isr.close();            is.close();            socket.close();            serverSocket.close();        } catch (IOException e) {            e.printStackTrace();        }    }}
3-3 编程实现基于 TCP 的 Socket 通信之客户端
/** * 客户端 */public class Client {    public static void main(String[] args) {        try {            //1.创建客户端Socket,指定服务器端地址和端口            Socket socket = new Socket("localhost",8888);            //2.获取输出流,向服务器端发送信息            OutputStream os = socket.getOutputStream();//字节输出流            PrintWriter pw = new PrintWriter(os);//将输出流包装为打印流            pw.write("用户名:admin;密码:123");            pw.flush();            socket.shutdownOutput();//关闭输出流            //3.关闭资源            pw.close();            os.close();            socket.close();        } catch (UnknownHostException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }    }}
3-4 完善用户登陆之服务器响应客户端
/** * 基于TCP协议的socket通信,实现用户登录 * 服务器端 */public class Server {    public static void main(String[] args) {        try {            //1.创建一个服务器端Socket,即ServerSocket,指定绑定的端口            ServerSocket serverSocket = new ServerSocket(8888);            //2.调用accept()方法开始监听,等待客户端 的连接            System.out.println("***服务器即将启动,等待客户端的连接***");            Socket socket = serverSocket.accept();            //3.获取输入流,并读取客户端信息            InputStream is = socket.getInputStream();//字节输入流            InputStreamReader isr = new InputStreamReader(is);//将字节输入流转换为字符流            BufferedReader br = new BufferedReader(isr);//为输入流添加缓冲            String info = null;            while((info=br.readLine())!=null) {//循环读取客户端的信息                System.out.println("我是服务器,客户端说:"+info);            }            socket.shutdownInput();//关闭输入流            //4.获取输出流,响应客户端请求            OutputStream op = socket.getOutputStream();            PrintWriter pw = new PrintWriter(op);//包装为打印流            pw.write("欢迎您!");            pw.flush();            //5.关闭资源            pw.close();            op.close();            br.close();            isr.close();            is.close();            socket.close();            serverSocket.close();        } catch (IOException e) {            e.printStackTrace();        }    }}
/** * 客户端 */public class Client {    public static void main(String[] args) {        try {            //1.创建客户端Socket,指定服务器端地址和端口            Socket socket = new Socket("localhost",8888);            //2.获取输出流,向服务器端发送信息            OutputStream os = socket.getOutputStream();//字节输出流            PrintWriter pw = new PrintWriter(os);//将输出流包装为打印流            pw.write("用户名:admin;密码:123");            pw.flush();            socket.shutdownOutput();//关闭输出流            //3.获取输入流,并读取服务器的响应信息            InputStream is = socket.getInputStream();            BufferedReader br = new BufferedReader(new InputStreamReader(is));            String info = null;            while((info = br.readLine()) != null) {                System.out.println("我是客户端,服务器端说:"+info);            }            //4.关闭资源            br.close();            is.close();            pw.close();            os.close();            socket.close();        } catch (UnknownHostException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }    }}
3-5 使用多线程实现多客户端的通信
/* * 服务器线程处理类 */public class ServerThread extends Thread {    // 和本线程相关的Socket    Socket socket = null;    public ServerThread(Socket socket) {        this.socket = socket;    }    //线程执行的操作,响应客户端的请求    public void run(){        InputStream is=null;        InputStreamReader isr=null;        BufferedReader br=null;        OutputStream os=null;        PrintWriter pw=null;        try {            //获取输入流,并读取客户端信息            is = socket.getInputStream();            isr = new InputStreamReader(is);            br = new BufferedReader(isr);            String info=null;            while((info=br.readLine())!=null){//循环读取客户端的信息                System.out.println("我是服务器,客户端说:"+info);            }            socket.shutdownInput();//关闭输入流            //获取输出流,响应客户端的请求            os = socket.getOutputStream();            pw = new PrintWriter(os);            pw.write("欢迎您!");            pw.flush();//调用flush()方法将缓冲输出        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }finally{            //关闭资源            try {                if(pw!=null)                    pw.close();                if(os!=null)                    os.close();                if(br!=null)                    br.close();                if(isr!=null)                    isr.close();                if(is!=null)                    is.close();                if(socket!=null)                    socket.close();            } catch (IOException e) {                e.printStackTrace();            }        }    }}
/* * 基于TCP协议的Socket通信,实现用户登陆 * 服务器端 */public class Server {    public static void main(String[] args) {        try {            //1.创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口            ServerSocket serverSocket=new ServerSocket(8888);            Socket socket=null;            //记录客户端的数量            int count=0;            System.out.println("***服务器即将启动,等待客户端的连接***");            //循环监听等待客户端的连接            while(true){                //调用accept()方法开始监听,等待客户端的连接                socket=serverSocket.accept();                //创建一个新的线程                ServerThread serverThread=new ServerThread(socket);                //启动线程                serverThread.start();                count++;//统计客户端的数量                System.out.println("客户端的数量:"+count);                InetAddress address=socket.getInetAddress();                System.out.println("当前客户端的IP:"+address.getHostAddress());            }        } catch (IOException e) {            e.printStackTrace();        }    }}
/* * 客户端 */public class Client {    public static void main(String[] args) {        try {            //1.创建客户端Socket,指定服务器地址和端口            Socket socket=new Socket("localhost", 8888);            //2.获取输出流,向服务器端发送信息            OutputStream os=socket.getOutputStream();//字节输出流            PrintWriter pw=new PrintWriter(os);//将输出流包装为打印流            pw.write("用户名:admin;密码:123");            pw.flush();            socket.shutdownOutput();//关闭输出流            //3.获取输入流,并读取服务器端的响应信息            InputStream is=socket.getInputStream();            BufferedReader br=new BufferedReader(new InputStreamReader(is));            String info=null;            while((info=br.readLine())!=null){                System.out.println("我是客户端,服务器说:"+info);            }            //4.关闭资源            br.close();            is.close();            pw.close();            os.close();            socket.close();        } catch (UnknownHostException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }    }}
第4章 通过 Socket 实现 UDP 编程
4-1 DatagramPacket

UDP编程
- UDP协议(用户数据报协议)是无连接的、不可靠的,无序的
- UDP协议以数据报作为数据传输的载体
- 进行数据传输时,首先需要将要传输的数据定义成
数据报(Datagram),在数据报中指明数据所要达到的
Socket(主机地址和端口号),然后在将数据报发送出去

相关操作类
- DatagramPacket:表示数据报包
- DatagramSocket:进行端到端通信的类

Class DatagramPacket
java.lang.Object
java.net.DatagramPacket

这类表示一个数据报包。

构造方法 Constructor and Description DatagramPacket(byte[] buf, int length) 接收数据包长度 length DatagramPacket构建。 DatagramPacket(byte[] buf, int length, InetAddress address, int port) 指定主机上的指定端口发送数据包的长度 length数据报包结构。 DatagramPacket(byte[] buf, int offset, int length) 接收数据包长度 length DatagramPacket结构,指定一个偏移量到缓冲区。 DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) 发送有偏置 ioffsetto指定端口号指定主机上的数据包长度 length数据报包结构。 DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) 发送有偏置 ioffsetto指定端口号指定主机上的数据包长度 length数据报包结构。 DatagramPacket(byte[] buf, int length, SocketAddress address) 指定主机上的指定端口发送数据包的长度 length数据报包结构。 Modifier and Type Method and Description InetAddress getAddress()
返回的IP地址的机器,这个数据包被发送或从收到的数据报。 byte[] getData()
返回数据缓冲区。 int getLength()
返回要发送的数据的长度或收到的数据的长度。 int getOffset()
返回所要发送的数据的偏移量或所接收的数据的偏移量。 int getPort()
返回远端端口号,这个数据包被发送或从收到的数据报。 SocketAddress getSocketAddress()
获取SocketAddress(通常是IP地址+端口号)的远程主机,数据包被发送到或来自。 void setAddress(InetAddress iaddr)
设置本机的IP地址,这个数据包被发送。 void setData(byte[] buf)
为这个数据包设置数据缓冲区。 void setData(byte[] buf, int offset, int length)
为这个数据包设置数据缓冲区。 void setLength(int length)
为这个数据包设置长度。 void setPort(int iport)
设置远端端口号,这个数据包被发送。 void setSocketAddress(SocketAddress address)
集SocketAddress(通常是IP地址+端口号)的远程主机的数据报发送。

Class DatagramSocket
java.lang.Object
java.net.DatagramSocket

这类代表一个发送和接收数据包的插座。

构造方法 Modifier Constructor and Description DatagramSocket() 构建一个数据报套接字绑定到本地主机的任何可用的端口。 DatagramSocket(DatagramSocketImpl impl) 创建一个绑定的数据报套接字与指定的datagramsocketimpl。 DatagramSocket(int port) 构建一个数据报套接字绑定到本地主机的指定端口。 DatagramSocket(int port, InetAddress laddr) 创建一个数据报套接字,绑定到指定的本地地址。 DatagramSocket(SocketAddress bindaddr) 创建一个数据报套接字,绑定到指定的本地套接字地址。 Modifier and Type Method and Description void bind(SocketAddress addr)
结合这个DatagramSocket到特定的地址和端口。 void close()
关闭该数据报套接字。 void connect(InetAddress address, int port)
将套接字连接到这个套接字的远程地址。 void connect(SocketAddress addr)
将此套接字连接到远程套接字地址(IP地址+端口号)。 void disconnect()
断开插座。 boolean getBroadcast()
如果so_broadcast启用。 DatagramChannel getChannel()
返回与此数据报套接字相关的独特的 DatagramChannel对象,如果任何。 InetAddress getInetAddress()
返回此套接字连接的地址。 InetAddress getLocalAddress()
获取绑定的套接字的本地地址。 int getLocalPort()
返回此套接字绑定的本地主机上的端口号。 SocketAddress getLocalSocketAddress()
返回此套接字绑定到的端点的地址。 int getPort()
返回此套接字连接的端口号。 int getReceiveBufferSize()
得到这个 DatagramSocket的so_rcvbuf期权价值,即通过平台用于该 DatagramSocket输入缓冲区的大小。 SocketAddress getRemoteSocketAddress()
返回此套接字连接的端点的地址,或如果它是无关的 null。 boolean getReuseAddress()
如果so_reuseaddr启用。 int getSendBufferSize()
得到这个 DatagramSocket的so_sndbuf期权价值,即缓冲区的大小由平台用于输出在这 DatagramSocket。 int getSoTimeout()
检索设置so_timeout。 int getTrafficClass()
获取交通类或类型的服务在IP数据报头的DatagramSocket发送的数据包。 boolean isBound()
返回套接字的绑定状态。 boolean isClosed()
返回套接字是否关闭或不关闭的。 boolean isConnected()
返回套接字的连接状态。 void receive(DatagramPacket p)
接收数据报包从这个插座。 void send(DatagramPacket p)
从这个套接字发送数据报包。 void setBroadcast(boolean on)
启用/禁用so_broadcast。 static void setDatagramSocketImplFactory(DatagramSocketImplFactory fac)
集的数据报套接字实现工厂的应用。 void setReceiveBufferSize(int size)
集so_rcvbuf选项,这 DatagramSocket指定值。 void setReuseAddress(boolean on)
启用/禁用so_reuseaddr套接字选项。 void setSendBufferSize(int size)
集so_sndbuf选项,这 DatagramSocket指定值。 void setSoTimeout(int timeout)
启用/禁用so_timeout以指定的超时时间,以毫秒为单位。 void setTrafficClass(int tc)
集交通类或从这个DatagramSocket发送数据报的IP数据报头字节型服务。
4-2 编程实现基于 UDP的 Socket 通信之服务器端
  • 服务端实现步骤

    1. 创建DatagramSocket,指定端口号
    2. 创建DatagramPacket
    3. 接收客户端发送的数据信息
    4. 读取信息
  • 客户端实现步骤

    1. 定义发送信息
    2. 创建DatagramPacket,包含将要发送的信息
    3. 创建DatagramSocket
    4. 发送数据
/* * 服务器端,实现基于UDP的用户登录 */public class UDPServer {    public static void main(String[] args) throws IOException {        //1.创建服务端DatagramSocket,指定端口        DatagramSocket socket = new DatagramSocket(8800);        //2.创建数据报,用于接收客户端发送的数据        byte[] data = new byte[1024];        DatagramPacket packet = new DatagramPacket(data,data.length);        //3.接收客户端发送的数据        socket.receive(packet);//此方法在接收数据报之前会一直阻塞        //4.读取数据        String info = new String(data,0,packet.getLength());        System.out.println("我是服务器,客户端说:"+info);    }}
4-3 编程实现基于 UDP 的 Socket 通信之客户端
/* * 客户端 */public class UDPClient0 {    public static void main(String[] args) throws IOException {        //1.定义服务器的地址、端口号、数据        InetAddress address = InetAddress.getByName("localhost");        int port = 8800;        byte[] data = "用户名:admin;密码:123".getBytes();        //2.创建数据报,包含发送的数据信息        DatagramPacket packet = new DatagramPacket(data, data.length,address,port);        //3.创建DatagramSocket对象        DatagramSocket socket = new DatagramSocket();        //4.向服务器端发送数据报        socket.send(packet);    }}
/* * 服务器端,实现基于UDP的用户登陆 */public class UDPServer {    public static void main(String[] args) throws IOException {        /*         * 接收客户端发送的数据         */        //1.创建服务器端DatagramSocket,指定端口        DatagramSocket socket=new DatagramSocket(8800);        //2.创建数据报,用于接收客户端发送的数据        byte[] data =new byte[1024];//创建字节数组,指定接收的数据包的大小        DatagramPacket packet=new DatagramPacket(data, data.length);        //3.接收客户端发送的数据        System.out.println("****服务器端已经启动,等待客户端发送数据");        socket.receive(packet);//此方法在接收到数据报之前会一直阻塞        //4.读取数据        String info=new String(data, 0, packet.getLength());        System.out.println("我是服务器,客户端说:"+info);        /*         * 向客户端响应数据         */        //1.定义客户端的地址、端口号、数据        InetAddress address=packet.getAddress();        int port=packet.getPort();        byte[] data2="欢迎您!".getBytes();        //2.创建数据报,包含响应的数据信息        DatagramPacket packet2=new DatagramPacket(data2, data2.length, address, port);        //3.响应客户端        socket.send(packet2);        //4.关闭资源        socket.close();    }}
/* * 客户端 */public class UDPClient {    public static void main(String[] args) throws IOException {        /*         * 向服务器端发送数据         */        //1.定义服务器的地址、端口号、数据        InetAddress address=InetAddress.getByName("localhost");        int port=8800;        byte[] data="用户名:admin;密码:123".getBytes();        //2.创建数据报,包含发送的数据信息        DatagramPacket packet=new DatagramPacket(data, data.length, address, port);        //3.创建DatagramSocket对象        DatagramSocket socket=new DatagramSocket();        //4.向服务器端发送数据报        socket.send(packet);        /*         * 接收服务器端响应的数据         */        //1.创建数据报,用于接收服务器端响应的数据        byte[] data2=new byte[1024];        DatagramPacket packet2=new DatagramPacket(data2, data2.length);        //2.接收服务器响应的数据        socket.receive(packet2);        //3.读取数据        String reply=new String(data2, 0, packet2.getLength());        System.out.println("我是客户端,服务器说:"+reply);        //4.关闭资源        socket.close();    }}
第5章 Socket 总结
5-1 Socket 总结

重点
- Socket通信原理
- 基于TCP的Socket通信

  1. 多线程的优先级
    未设置优先级可能会导致运行速度非常慢,可降低优先级
  2. 是否关闭输入流和输出流
    对于同一个socket,如果关闭了输出流,则与该输出流关联的
    socket也会被关闭,所有一般不用关闭流,直接关闭socket即可
  3. 使用TCP通信传输对象
    ObjectOutputStream oos = new ObjectOutputStream(os);
    oos.writeObject(user);
  4. socket编程传递文件
    BufferedOutputStream fos new BufferedOutputStream(new FileOutputStream(filename));
第6章 综合练习
6-1 综合练习—问题描述
6-2 综合练习—实现分析

Java Socket应用—通信是这样练成的视频地址

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 把罚款单弄丢了怎么办 在12306买不到下铺怎么办有 地铁票买反了怎么办 香港买错特惠票怎么办 到达迪拜t3 后怎么办 海藻面膜调多了怎么办 被鸡爪子抓伤了怎么办 被鸡抓伤肿了怎么办 护士电子化没有激活码怎么办 窗帘盒螺丝掉了怎么办 窗帘的环扣掉了怎么办 门式起重吊装行车脱轨怎么办 在日本丢了东西怎么办 在日本钱包丢了怎么办 被起诉后没钱还怎么办 分期付款卖车打不起车款怎么办 地铁票买多了怎么办 工伤陪护费没有发票怎么办 工伤医疗费报销单位不盖章怎么办 家里的led灯坏了怎么办 吊顶led灯坏了怎么办 客厅空了一面墙怎么办 轨道灯的轨道不够长怎么办 奔驰大灯不亮了怎么办 led顶灯不亮了怎么办 吸顶灯led灯坏了怎么办 车底盘塑料被刮怎么办 汽车门电机坏了怎么办 宁波北仑普高差三分该怎么办 上班的地方甲醛味很重怎么办 公司不给员工交社保怎么办 户口转到学校毕业了怎么办 外地户口转到北京档案怎么办 隧道防水板过紧怎么办 到国企没报到证怎么办 车子锁了油箱盖能开怎么办 单位不接受档案和户口怎么办 完税凭证弄丢了怎么办 育种玉米公本早了怎么办 网银转账打错了怎么办 转账名字打错了怎么办