12.1 基本概念


如今,计算机已经成为人们学习、工作、生活必不可少的工具。我们利用计算机可以和亲朋好友网上聊天,也可以玩网游、发邮件等等,这些功能实现都离不开计算机网络。计算机网络实现了不同计算机之间的通信,这必须依靠编写网络程序来实现。下面,我们将教大家如何编写网络程序
在学习编程之前,我们首先要了解关于网络通信的一些概念。

什么是计算机网络?

计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。

从其中我们可以提取到以下内容:
1.计算机网络的作用:资源共享、信息传递、负载均衡与分布处理
2.计算机网络的组成:
a) 计算机硬件:计算机(大中小型服务器,台式机、笔记本等)、外部设备(路由器、交换机等)、通信线路(双绞线、光纤等)。
b) 计算机软件:网络操作系统(Windows 2000 Server/Advance Server、Unix、Linux等)、网络管理软件(WorkWin、SugarNMS等)、网络通信协议(如TCP/IP协议栈等)。
3. 计算机网络的多台计算机是具有独立功能的,而不是脱离网络就无法存在的。

什么是网络通信协议?

通过计算机网络可以实现不同计算机之间的连接与通信,但是计算机网络中实现通信必须有一些约定即通信协议,对速率、传输代码、代码结构、传输控制步骤、出错控制等制定标准。就像两个人想要顺利沟通就必须使用同一种语言一样,如果一个人只懂英语而另外一个人只懂中文,这样就会造成没有共同语言而无法沟通。

国际标准化组织(ISO,即International Organization for Standardization)定义了网络通信协议的基本框架,被称为OSI(Open System Interconnect,即开放系统互联)模型。要制定通讯规则,内容会很多,比如要考虑A电脑如何找到B电脑,A电脑在发送信息给B电脑时是否需要B电脑进行反馈,A电脑传送给B电脑的数据格式又是怎样的?内容太多太杂,所以OSI模型将这些通讯标准进行层次划分,每一层次解决一个类别的问题,这样就使得标准的制定没那么复杂。OSI模型制定的七层标准模型,分别是:应用层,表示层,会话层,传输层,网络层,数据链路层,物理层

OSI七层协议模型如图12-1所示:

虽然国际标准化组织制定了这样一个网络通信协议的模型,但是实际上互联网通讯使用最多的网络通信协议是TCP/IP网络通信协议。

TCP/IP 是一个协议族,也是按照层次划分,共四层:应用层,传输层,互连网络层,网络接口层(物理+数据链路层)
那么TCP/IP协议和OSI模型有什么区别呢?OSI网络通信协议模型,是一个参考模型,而TCP/IP协议是事实上的标准。TCP/IP协议参考了OSI 模型,但是并没有严格按照OSI规定的七层标准去划分,而只划分了四层,这样会更简单点,当划分太多层次时,你很难区分某个协议是属于哪个层次的。

TCP/IP协议和OSI模型也并不冲突,TCP/IP协议中的应用层协议,就对应于OSI中的应用层,表示层,会话层。就像以前有工业部和信息产业部,现在实行大部制后只有工业和信息化部一个部门,但是这个部门还是要做以前两个部门一样多的事情,本质上没有多大的差别。TCP/IP中有两个重要的协议,传输层的TCP协议和互连网络层的IP协议,因此就拿这两个协议做代表,来命名整个协议族了,再说TCP/IP协议时,是指整个协议族。

网络协议的分层

由于网络结点之间联系很复杂,在制定协议时,把复杂成份分解成一些简单的成份,再将它们复合起来。最常用的复合方式是层次方式,即同层间可以通信、上一层可以调用下一层,而与再下一层不发生关系。
把用户应用程序作为最高层,把物理通信线路作为最低层,将其间的协议处理分为若干层,规定每层处理的任务,也规定每层的接口标准。
ISO模型与TCP/IP模型的对应关系如图12-2所示。

数据封装与解封:

由于用户传输的数据一般都比较大,有的可以达到MB字节,一次性发送出去十分困难,于是就需要把数据分成许多片段,再按照一定的次序发送出去。这个过程就需要对数据进行封装。
数据封装(Data Encapsulation)是指将协议数据单元(PDU)封装在一组协议头和协议尾中的过程。在OSI七层参考模型中,每层主要负责与其它机器上的对等层进行通信。该过程是在协议数据单元(PDU)中实现的,其中每层的PDU一般由本层的协议头、协议尾和数据封装构成。

1.数据发送处理过程
(1)应用层将数据交给传输层,传输层添加上TCP的控制信息(称为TCP头部),这个数据单元称为段(Segment),加入控制信息的过程称为封装。然后,将段交给网络层。
(2)网络层接收到段,再添加上IP头部,这个数据单元称为包(Packet)。然后,将包交给数据链路层。
(3) 数据链路层接收到包,再添加上MAC头部和尾部,这个数据单元称为帧(Frame)。然后,将帧交给物理层。
(4)物理层将接收到的数据转化为比特流,然后在网线中传送。

2.数据接收处理过程
(1)物理层接收到比特流,经过处理后将数据交给数据链路层。
(2)数据链路层将接收到的数据转化为数据帧,再除去MAC头部和尾部,这个除去控制信息的过程称为解封,然后将包交给网络层。
(3)网络层接收到包,再除去IP头部,然后将段交给传输层。
(4)传输层接收到段,再除去TCP头部,然后将数据交给应用层。

从以上传输过程中,可以总结出以下规则:
(1)发送方数据处理的方式是从高层到底层,逐层进行数据封装
(2)接收方数据处理的方式是从底层到高层,逐层进行数据解封装
接收方的每一层只把对该层有意义的数据拿走,或者说每一层只能处理发送方同等层的数据,然后把其余的部分传递给上一层,这就是对等层通信的概念。

数据封装与解封如图12-3和图12-4所示:

IP地址:

定位:
IP定位电脑
Port定位软件
URL定位资源

用来标识网络中的一个通信实体的地址。通信实体可以是计算机、路由器等。 比如互联网的每个服务器都要有自己的IP地址,而每个局域网的计算机要通信也要配置IP地址。路由器是连接两个或多个网络的网络设备。
目前主流使用的IP地址是IPV4,但是随着网络规模的不断扩大,IPV4面临着枯竭的危险,所以推出了IPV6。

IPV4:32位地址,并以8位为一个单位,分成四部分,以点分十进制表示,如192.168.0.1。因为8位二进制的计数范围是00000000—11111111,对应十进制的0-255,所以-4.278.4.1是错误的IPV4地址。

IPV6:128位(16个字节)写成8个16位的无符号整数,每个整数用四个十六进制位表示,每个数之间用冒号(:)分开,如:3ffe:3201:1401:1280:c8ff:fe4d:db39:1984
IPTest.java

package com.sxt.loc;

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

/**

  • IP:定位一个节点:计算机、路由、通讯设备等
  • InetAddress: 多个静态方法
  • 1、getLocalHost:本机
  • 2、getByName:根据域名DNS | IP地址 -->IP
  • 两个成员方法
  • 1、getHostAddress: 返回地址
  • 2、getHostName:返回计算机名

*/
public class IPTest {

public static void main(String[] args) throws UnknownHostException {//使用getLocalHost方法创建InetAddress对象  本机InetAddress addr = InetAddress.getLocalHost();System.out.println(addr.getHostAddress());  //返回:192.168.1.110System.out.println(addr.getHostName());  //输出计算机名//根据域名得到InetAddress对象  DNS域名解析(将IP地址和有意义的字符串之间转换)addr = InetAddress.getByName("www.shsxt.com"); System.out.println(addr.getHostAddress());  //返回 shsxt服务器的ip地址123.56.138.186System.out.println(addr.getHostName());  //输出:www.shsxt.com//根据ip得到InetAddress对象addr = InetAddress.getByName("123.56.138.176"); System.out.println(addr.getHostAddress());  //返回 shsxt的ip:123.56.138.176System.out.println(addr.getHostName());  //输出ip而不是域名。如果这个IP地 址不存在或DNS服务器不允许进行IP地址和域名的映射,
}

}
注意事项
1.127.0.0.1 本机地址
2.192.168.0.0–192.168.255.255为私有地址,属于非注册地址,专门为组织机构内部使用。

端口:

IP地址用来标识一台计算机,但是一台计算机上可能提供多种网络应用程序,如何来区分这些不同的程序呢?这就要用到端口。0~65535
端口是虚拟的概念,并不是说在主机上真的有若干个端口。通过端口,可以在一个主机上运行多个网络应用程序。 端口的表示是一个16位的二进制整数对应十进制的0-65535。
Oracle、MySQL、Tomcat、QQ、msn、迅雷、电驴、360等网络程序都有自己的端口。

总结
1.IP地址好比每个人的地址(门牌号),端口好比是房间号。必须同时指定IP地址和端口号才能够正确的发送数据。
2. IP地址好比为电话号码,而端口号就好比为分机号。


PortTest.java

package com.sxt.loc;import java.net.InetSocketAddress;
/*** 端口* 1、区分软件* 2、2个字节 0-65535  UDP TCP* 3、同一个协议端口不能冲突* 4、定义端口越大越好* InetSocketAddress * 1、构造器*   new InetSocketAddress(地址|域名,端口);* 2、方法*  getAddress​()  返回地址*  getPort() 返回端口*  getHostName()  返回*/
public class PortTest {public static void main(String[] args) {//包含端口InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1",8080);InetSocketAddress socketAddress2 = new InetSocketAddress("localhost",9000);System.out.println(socketAddress.getHostName());System.out.println(socketAddress.getAddress());System.out.println(socketAddress2.getAddress());System.out.println(socketAddress2.getPort());}
}

URL:


在www上,每一信息资源都有统一且唯一的地址,该地址就叫URL(Uniform Resource Locator),它是www的统一资源定位符。
URL由4部分组成:协议 、存放资源的主机域名、资源文件名和端口号
如果未指定该端口号,则使用协议默认的端口。例如http 协议的默认端口为 80。 在浏览器中访问网页时,地址栏显示的地址就是URL。
在java.net包中提供了URL类,该类封装了大量复杂的涉及从远程站点获取信息的细节。
URLTest01.java

package com.sxt.loc;import java.net.MalformedURLException;
import java.net.URL;/*** URL: 统一资源定位器,互联网三大基石之一(html http),区分资源* 1、协议* 2、域名、计算机* 3、端口: 默认80* 4、请求资源*  http://www.baidu.com:80/index.html?uname=shsxt&age=18#a*/
public class URLTest01 {public static void main(String[] args) throws MalformedURLException {URL url = new URL("http://www.baidu.com:80/index.html?uname=shsxt&age=18#a");//获取四个值System.out.println("协议:"+url.getProtocol());System.out.println("域名|ip:"+url.getHost());System.out.println("端口:"+url.getPort());System.out.println("请求资源1:"+url.getFile());System.out.println("请求资源2:"+url.getPath());//参数System.out.println("参数:"+url.getQuery());//锚点System.out.println("锚点:"+url.getRef());}}


爬虫原理


SpiderTest01.java

package com.sxt.loc;import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;/*** 网络爬虫的原理*/
public class SpiderTest01 {public static void main(String[] args) throws Exception {//获取URLURL url =new URL("https://www.jd.com");//URL url =new URL("https://www.dianping.com");//下载资源InputStream is = url.openStream();BufferedReader br =new BufferedReader(new InputStreamReader(is,"UTF-8"));String msg =null;while(null!=(msg=br.readLine())) {System.out.println(msg);}br.close();//分析//处理。。。。}}

SpiderTest02.java
package com.sxt.loc;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

/**

  • 网络爬虫的原理 +模拟浏览器
    */
    public class SpiderTest02 {

    public static void main(String[] args) throws Exception {
    //获取URL
    URL url =new URL(“https://www.dianping.com”);
    //下载资源
    HttpURLConnection conn =(HttpURLConnection) url.openConnection();
    conn.setRequestMethod(“GET”);
    conn.setRequestProperty(“User-Agent”,“Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36”);
    BufferedReader br =new BufferedReader(new InputStreamReader(conn.getInputStream(),“UTF-8”));
    String msg =null;
    while(null!=(msg=br.readLine())) {
    System.out.println(msg);
    }
    br.close();
    //分析
    //处理。。。。
    }

}

Socket:

我们开发的网络应用程序位于应用层TCP和UDP属于传输层协议,在应用层如何使用传输层的服务呢?在应用层和传输层之间,则是使用套接Socket来进行分离。
相当于码头。

套接字就像是传输层为应用层开的一个小口,应用程序通过这个小口向远程发送数据,或者接收远程发来的数据;而这个小口以内,也就是数据进入这个口之后,或者数据从这个口出来之前,是不知道也不需要知道的,也不会关心它如何传输,这属于网络其它层次工作。

Socket实际是传输层供给应用层的编程接口。Socket就是应用层与传输层之间的桥梁。使用Socket编程可以开发客户机和服务器应用程序,可以在本地网络上进行通信,也可通过Internet在全球范围内通信。

12.2TCP UDP

12.2.1 TCP协议和UDP协议的联系和区别

TCP协议和UDP协议是传输层的两种协议。Socket是传输层供给应用层的编程接口,所以Socket编程就分为TCP编程和UDP编程两类。

在网络通讯中,TCP方式就类似于拨打电话,使用该种方式进行网络通讯时,需要建立专门的虚拟连接,然后进行可靠的数据传输,如果数据发送失败,则客户端会自动重发该数据。

而UDP方式就类似于发送短信,使用这种方式进行网络通讯时,不需要建立专门的虚拟连接,传输也不是很可靠,如果发送失败则客户端无法获得。

这两种传输方式都在实际的网络编程中使用,重要的数据一般使用TCP方式进行数据传输,而大量的非核心数据则可以通过UDP方式进行传递,在一些程序中甚至结合使用这两种方式进行数据传递。

由于TCP需要建立专用的虚拟连接以及确认传输是否正确,所以使用TCP方式的速度稍微慢一些,而且传输时产生的数据量要比UDP稍微大一些。

总结
1.TCP是面向连接的,传输数据安全,稳定,效率相对较低
2.UDP是面向无连接的,传输数据不安全,效率较高

12.2.2 TCP协议

TCP(Transfer Control Protocol)是面向连接的,所谓面向连接,就是当计算机双方通信时必需经过先建立连接,然后传送数据,最后拆除连接三个过程。

TCP在建立连接时又分三步走:
第一步,是请求端(客户端)发送一个包含SYN即同步(Synchronize)标志的TCP报文,SYN同步报文会指明客户端使用的端口以及TCP连接的初始序号。

第二步,服务器在收到客户端的SYN报文后,将返回一个SYN+ACK的报文,表示客户端的请求被接受,同时TCP序号被加一,ACK即确认(Acknowledgement)。

第三步,客户端也返回一个确认报文ACK给服务器端,同样TCP序列号被加一,到此一个TCP连接完成。然后才开始通信的第二步:数据处理。
这就是所说的TCP的三次握手(Three-way Handshake)。

基本步骤








例1:
Server.java

package com.sxt.tcp;import java.io.DataInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;/*** 熟悉流程* 创建服务器* 1、指定端口 使用ServerSocket创建服务器* 2、阻塞式等待连接 accept* 3、操作: 输入输出流操作* 4、释放资源 */
public class Server {public static void main(String[] args) throws IOException {System.out.println("-----Server-----");// 1、指定端口 使用ServerSocket创建服务器ServerSocket server =new ServerSocket(8888);// 2、阻塞式等待连接 acceptSocket  client =server.accept(); System.out.println("一个客户端建立了连接");// 3、操作: 输入输出流操作DataInputStream dis =new DataInputStream(client.getInputStream());String data =dis.readUTF();System.out.println(data);// 4、释放资源 dis.close();client.close();server.close();}}

Client.java

package com.sxt.tcp;import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;/*** 熟悉流程* 创建客户端* 1、建立连接: 使用Socket创建客户端 +服务的地址和端口* 2、操作: 输入输出流操作* 3、释放资源 */
public class Client {public static void main(String[] args) throws UnknownHostException, IOException {System.out.println("-----Client-----");//1、建立连接: 使用Socket创建客户端 +服务的地址和端口Socket client =new Socket("localhost",8888);//2、操作: 输入输出流操作DataOutputStream dos =new DataOutputStream(client.getOutputStream());String data ="hello";dos.writeUTF(data);dos.flush();//3、释放资源 dos.close();client.close();}}

文件上传


例2:单向的
LoginServer.java

package com.sxt.tcp;import java.io.DataInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;/*** 模拟登录 单向* 创建服务器* 1、指定端口 使用ServerSocket创建服务器* 2、阻塞式等待连接 accept* 3、操作: 输入输出流操作* 4、释放资源 */
public class LoginServer {public static void main(String[] args) throws IOException {System.out.println("-----Server-----");// 1、指定端口 使用ServerSocket创建服务器ServerSocket server =new ServerSocket(8888);// 2、阻塞式等待连接 acceptSocket  client =server.accept(); System.out.println("一个客户端建立了连接");// 3、操作: 输入输出流操作DataInputStream dis =new DataInputStream(client.getInputStream());String datas =dis.readUTF();//分析String[] dataArray = datas.split("&");for(String info:dataArray) {String[] userInfo =info.split("=");if(userInfo[0].equals("uname")) {System.out.println("你的用户名为:"+userInfo[1]);}else if(userInfo[0].equals("upwd")) {System.out.println("你的密码为:"+userInfo[1]);}}// 4、释放资源 dis.close();client.close();server.close();}}

LoginClient.java

package com.sxt.tcp;import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;/*** 模拟登录 单向* 创建客户端* 1、建立连接: 使用Socket创建客户端 +服务的地址和端口* 2、操作: 输入输出流操作* 3、释放资源 */
public class LoginClient {public static void main(String[] args) throws UnknownHostException, IOException {System.out.println("-----Client-----");BufferedReader console =new BufferedReader(new InputStreamReader(System.in));System.out.print("请输入用户名:");String uname =console.readLine();System.out.print("请输入密码:");String upwd =console.readLine();//1、建立连接: 使用Socket创建客户端 +服务的地址和端口Socket client =new Socket("localhost",8888);//2、操作: 输入输出流操作DataOutputStream dos =new DataOutputStream(client.getOutputStream());      dos.writeUTF("uname="+uname+"&"+"upwd="+upwd);dos.flush();//3、释放资源 dos.close();client.close();}}


例3:双向的
LoginTwoWayServer.java

package com.sxt.tcp;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;/*** 模拟登录 双向* 创建服务器* 1、指定端口 使用ServerSocket创建服务器* 2、阻塞式等待连接 accept* 3、操作: 输入输出流操作* 4、释放资源 */
public class LoginTwoWayServer {public static void main(String[] args) throws IOException {System.out.println("-----Server-----");// 1、指定端口 使用ServerSocket创建服务器ServerSocket server =new ServerSocket(8888);// 2、阻塞式等待连接 acceptSocket  client =server.accept(); System.out.println("一个客户端建立了连接");// 3、操作: 输入输出流操作DataInputStream dis =new DataInputStream(client.getInputStream());String datas =dis.readUTF();String uname ="";String upwd ="";//分析String[] dataArray = datas.split("&");for(String info:dataArray) {String[] userInfo =info.split("=");if(userInfo[0].equals("uname")) {System.out.println("你的用户名为:"+userInfo[1]);uname = userInfo[1];}else if(userInfo[0].equals("upwd")) {System.out.println("你的密码为:"+userInfo[1]);upwd = userInfo[1];}             }//输出DataOutputStream dos =new DataOutputStream(client.getOutputStream());         if(uname.equals("shsxt") && upwd.equals("laopei")) { //成功dos.writeUTF("登录成功,欢迎回来");}else { //失败dos.writeUTF("用户名或密码错误");}dos.flush();// 4、释放资源 dis.close();client.close();server.close();}}

LoginTwoWayClient.java

package com.sxt.tcp;import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;/*** 模拟登录 双向* 创建客户端* 1、建立连接: 使用Socket创建客户端 +服务的地址和端口* 2、操作: 输入输出流操作* 3、释放资源 */
public class LoginTwoWayClient {public static void main(String[] args) throws UnknownHostException, IOException {System.out.println("-----Client-----");BufferedReader console =new BufferedReader(new InputStreamReader(System.in));System.out.print("请输入用户名:");String uname =console.readLine();System.out.print("请输入密码:");String upwd =console.readLine();//1、建立连接: 使用Socket创建客户端 +服务的地址和端口Socket client =new Socket("localhost",8888);//2、操作: 输入输出流操作DataOutputStream dos =new DataOutputStream(client.getOutputStream());        dos.writeUTF("uname="+uname+"&"+"upwd="+upwd);dos.flush();DataInputStream dis =new DataInputStream(client.getInputStream());String result =dis.readUTF();     System.out.println(result);//3、释放资源 dos.close();client.close();}}


1.只能输入一次
2.先输入才能获取

例4:文件
FileServer.java

package com.sxt.tcp;import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;/*** 存储文件* 创建服务器* 1、指定端口 使用ServerSocket创建服务器* 2、阻塞式等待连接 accept* 3、操作: 输入输出流操作* 4、释放资源 */
public class FileServer {public static void main(String[] args) throws IOException {System.out.println("-----Server-----");// 1、指定端口 使用ServerSocket创建服务器ServerSocket server =new ServerSocket(8888);// 2、阻塞式等待连接 acceptSocket  client =server.accept(); System.out.println("一个客户端建立了连接");// 3、操作: 文件拷贝 存储InputStream is =new BufferedInputStream(client.getInputStream());OutputStream os =new BufferedOutputStream(new FileOutputStream("src/tcp.png"));byte[] flush =new byte[1024];int len = -1;while((len=is.read(flush))!=-1) {os.write(flush,0,len);}os.flush();//3、释放资源 os.close();is.close();// 4、释放资源 client.close();server.close();}}

FileClient.java

package com.sxt.tcp;import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;/*** 上传文件* 创建客户端* 1、建立连接: 使用Socket创建客户端 +服务的地址和端口* 2、操作: 输入输出流操作* 3、释放资源 */
public class FileClient {public static void main(String[] args) throws UnknownHostException, IOException {System.out.println("-----Client-----");//1、建立连接: 使用Socket创建客户端 +服务的地址和端口Socket client =new Socket("localhost",8888);//2、操作: 拷贝 上传InputStream is =new BufferedInputStream(new FileInputStream("src/ndl.png"));OutputStream os =new BufferedOutputStream(client.getOutputStream());byte[] flush =new byte[1024];int len = -1;while((len=is.read(flush))!=-1) {os.write(flush,0,len);}os.flush();//3、释放资源 os.close();is.close();client.close();}}

多用户登陆

LoginMultiServer.java

package com.sxt.tcp;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;/*** 模拟登录 多个客户端请求* 创建服务器* 1、指定端口 使用ServerSocket创建服务器* 2、阻塞式等待连接 accept* 3、操作: 输入输出流操作* 4、释放资源 */
public class LoginMultiServer {public static void main(String[] args) throws IOException {System.out.println("-----Server-----");// 1、指定端口 使用ServerSocket创建服务器ServerSocket server =new ServerSocket(8888);boolean isRunning =true;;// 2、阻塞式等待连接 acceptwhile(isRunning) {Socket  client =server.accept(); System.out.println("一个客户端建立了连接");new Thread(new Channel(client)).start();}server.close();}//一个channel就代表一个客户端static class Channel implements Runnable{private Socket  client;//输入流private DataInputStream dis;//输出流private DataOutputStream dos;public Channel(Socket  client) {this.client = client;try {//输入dis = new DataInputStream(client.getInputStream());//输出dos =new DataOutputStream(client.getOutputStream());    } catch (IOException e) {e.printStackTrace();release();}}//接收数据private String receive() {String datas ="";try {datas = dis.readUTF();} catch (IOException e) {e.printStackTrace();}return datas;}//释放资源private void release() {// 4、释放资源 try {if(null != dos) {dos.close();                    }} catch (IOException e) {e.printStackTrace();}try {if(null != dis) {dis.close();}} catch (IOException e) {e.printStackTrace();}try {if(null != client) {client.close();}} catch (IOException e) {e.printStackTrace();}}//发送数据private void send(String msg) {try {dos.writeUTF(msg);dos.flush();} catch (IOException e) {e.printStackTrace();}}@Overridepublic void run() {                      // 3、操作: 输入输出流操作                    String uname ="";String upwd ="";//分析String[] dataArray = receive().split("&");for(String info:dataArray) {String[] userInfo =info.split("=");if(userInfo[0].equals("uname")) {System.out.println("你的用户名为:"+userInfo[1]);uname = userInfo[1];}else if(userInfo[0].equals("upwd")) {System.out.println("你的密码为:"+userInfo[1]);upwd = userInfo[1];}               }                   if(uname.equals("shsxt") && upwd.equals("laopei")) { //成功send("登录成功,欢迎回来");}else { //失败send("用户名或密码错误");}release();}}
}

LoginMultiClient.java

package com.sxt.tcp;import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;/*** 模拟登录  多个客户端请求* 创建客户端* 1、建立连接: 使用Socket创建客户端 +服务的地址和端口* 2、操作: 输入输出流操作* 3、释放资源 */
public class LoginMultiClient {public static void main(String[] args) throws UnknownHostException, IOException {        System.out.println("-----Client-----");//1、建立连接: 使用Socket创建客户端 +服务的地址和端口Socket client =new Socket("localhost",8888);//2、操作: 输入输出流操作  先请求后响应new Send(client).send();new Receive(client).receive();     client.close();}//发送static class Send{private Socket client;private DataOutputStream dos;private BufferedReader console ;private String msg;public Send(Socket client) {            console=new BufferedReader(new InputStreamReader(System.in));this.msg =init();this.client = client;try {dos=new DataOutputStream(client.getOutputStream());} catch (IOException e) {e.printStackTrace();}}private String init() {                   try {System.out.print("请输入用户名:");String uname =console.readLine();System.out.print("请输入密码:");String upwd =console.readLine();return "uname="+uname+"&"+"upwd="+upwd;} catch (IOException e) {e.printStackTrace();}return "";            }public void send() {try {dos.writeUTF(msg);dos.flush();} catch (IOException e) {e.printStackTrace();}}}//接收static class Receive{private Socket client;private DataInputStream dis;public Receive(Socket client) {this.client = client;try {dis=new DataInputStream(client.getInputStream());} catch (IOException e) {e.printStackTrace();}}      public void receive() {String result;try {result = dis.readUTF();System.out.println(result);} catch (IOException e) {e.printStackTrace();}     }}
}

手写聊天室_基础简易版



群聊:聊天室就是一个转发器
私聊:报文,遍历找到它
容器上面,遍历所有容器还是找到一个

先请求后响应已经不行了,不能你说完一句我才能说。所以需要多线程。
例1:
Client.java

package com.sxt.chat01;import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;/*** 在线聊天室: 客户端* 目标: 实现一个客户可以正常收发消息*/
public class Client {public static void main(String[] args) throws UnknownHostException, IOException {System.out.println("-----Client-----");//1、建立连接: 使用Socket创建客户端 +服务的地址和端口Socket client =new Socket("localhost",8888);//2、客户端发送消息 输出流BufferedReader console =new BufferedReader(new InputStreamReader(System.in));String msg = console.readLine();DataOutputStream dos =new DataOutputStream(client.getOutputStream());        dos.writeUTF(msg);dos.flush();//3、获取消息DataInputStream dis =new DataInputStream(client.getInputStream());msg =dis.readUTF();System.out.println(msg);dos.close();dis.close();client.close();}
}

Chat.java

package com.sxt.chat01;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;/*** 在线聊天室: 服务器* 目标: 实现一个客户可以正常收发消息*/
public class Chat {public static void main(String[] args) throws IOException {System.out.println("-----Server-----");// 1、指定端口 使用ServerSocket创建服务器ServerSocket server =new ServerSocket(8888);// 2、阻塞式等待连接 acceptSocket  client =server.accept(); System.out.println("一个客户端建立了连接");//3、接收消息DataInputStream dis =new DataInputStream(client.getInputStream());String msg =dis.readUTF();//4、返回消息DataOutputStream dos =new DataOutputStream(client.getOutputStream());       dos.writeUTF(msg);//释放资源dos.flush();dos.close();dis.close();client.close();}
}

我发出去又给我返回来

例2:
要发多条
MultiChat.java

package com.sxt.chat01;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;/*** 在线聊天室: 服务器* 目标: 实现一个客户可以正常收发多条消息 */
public class MultiChat {public static void main(String[] args) throws IOException {System.out.println("-----Server-----");// 1、指定端口 使用ServerSocket创建服务器ServerSocket server =new ServerSocket(8888);// 2、阻塞式等待连接 acceptSocket  client =server.accept(); System.out.println("一个客户端建立了连接");DataInputStream dis =new DataInputStream(client.getInputStream());DataOutputStream dos =new DataOutputStream(client.getOutputStream());     boolean isRunning = true;while(isRunning) {//3、接收消息String msg =dis.readUTF();//4、返回消息dos.writeUTF(msg);//释放资源dos.flush();}dos.close();dis.close();client.close();}
}

MultiClient.java

package com.sxt.chat01;import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;/*** 在线聊天室: 客户端* 目标: 实现一个客户可以正常收发多条消息 */
public class MultiClient {public static void main(String[] args) throws UnknownHostException, IOException {System.out.println("-----Client-----");//1、建立连接: 使用Socket创建客户端 +服务的地址和端口Socket client =new Socket("localhost",8888);//2、客户端发送消息BufferedReader console =new BufferedReader(new InputStreamReader(System.in));DataOutputStream dos =new DataOutputStream(client.getOutputStream());        DataInputStream dis =new DataInputStream(client.getInputStream());boolean isRunning = true;while(isRunning) {String msg = console.readLine();dos.writeUTF(msg);dos.flush();//3、获取消息msg =dis.readUTF();System.out.println(msg);}dos.close();dis.close();client.close();}
}


只能一个人,现在想让多个客户正常的收发消息
例3:
MultiChat.java

package com.sxt.chat02;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;/*** 在线聊天室: 服务器* 目标: 实现多个客户可以正常收发多条消息 * 问题: 其他客户必须等待之前的客户退出,才能继续    排队  */
public class MultiChat {public static void main(String[] args) throws IOException {System.out.println("-----Server-----");// 1、指定端口 使用ServerSocket创建服务器ServerSocket server =new ServerSocket(8888);// 2、阻塞式等待连接 acceptwhile(true) {Socket  client =server.accept(); System.out.println("一个客户端建立了连接");DataInputStream dis =new DataInputStream(client.getInputStream());DataOutputStream dos =new DataOutputStream(client.getOutputStream());        boolean isRunning = true;while(isRunning) {//3、接收消息String msg =dis.readUTF();//4、返回消息dos.writeUTF(msg);//释放资源dos.flush();}dos.close();dis.close();client.close();}}
}

MultiClient.java

package com.sxt.chat02;import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;/*** 在线聊天室: 客户端* 目标: 实现多个客户可以正常收发多条消息 * 问题: 其他客户必须等待之前的客户退出,才能继续 排队*/
public class MultiClient {public static void main(String[] args) throws UnknownHostException, IOException {System.out.println("-----Client-----");//1、建立连接: 使用Socket创建客户端 +服务的地址和端口Socket client =new Socket("localhost",8888);//2、客户端发送消息BufferedReader console =new BufferedReader(new InputStreamReader(System.in));DataOutputStream dos =new DataOutputStream(client.getOutputStream());        DataInputStream dis =new DataInputStream(client.getInputStream());boolean isRunning = true;while(isRunning) {String msg = console.readLine();dos.writeUTF(msg);dos.flush();//3、获取消息msg =dis.readUTF();System.out.println(msg);}dos.close();dis.close();client.close();}
}

有问题,一个客户占上以后,等他退出后,下一个客户才能用
例4:加上多线程
TMultiChat.java

package com.sxt.chat02;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;/*** 在线聊天室: 服务器* 目标: 使用多线程实现多个客户可以正常收发多条消息 * 问题: * 1、代码不好维护* 2、客户端读写没有分开 必须先写后读*/
public class TMultiChat {public static void main(String[] args) throws IOException {System.out.println("-----Server-----");// 1、指定端口 使用ServerSocket创建服务器ServerSocket server =new ServerSocket(8888);// 2、阻塞式等待连接 acceptwhile(true) {Socket  client =server.accept(); System.out.println("一个客户端建立了连接");new Thread(()->{DataInputStream dis=null;DataOutputStream dos=null;try {dis = new DataInputStream(client.getInputStream());dos =new DataOutputStream(client.getOutputStream());} catch (IOException e1) {e1.printStackTrace();}                  boolean isRunning = true;while(isRunning) {//3、接收消息String msg;try {msg = dis.readUTF();//4、返回消息dos.writeUTF(msg);//释放资源dos.flush();} catch (IOException e) {//e.printStackTrace();isRunning = false; //停止线程}                 }try {if(null==dos) {dos.close();}} catch (IOException e) {e.printStackTrace();}try {if(null==dis) {dis.close();}} catch (IOException e) {e.printStackTrace();}try {if(null==client) {client.close();}} catch (IOException e) {e.printStackTrace();}}).start(); }}

}

TMultiClient.java

package com.sxt.chat02;import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;/*** 在线聊天室: 客户端* 目标: 使用多线程实现多个客户可以正常收发多条消息 */
public class TMultiClient {public static void main(String[] args) throws UnknownHostException, IOException {System.out.println("-----Client-----");//1、建立连接: 使用Socket创建客户端 +服务的地址和端口Socket client =new Socket("localhost",8888);//2、客户端发送消息BufferedReader console =new BufferedReader(new InputStreamReader(System.in));DataOutputStream dos =new DataOutputStream(client.getOutputStream());       DataInputStream dis =new DataInputStream(client.getInputStream());boolean isRunning = true;while(isRunning) {String msg = console.readLine();dos.writeUTF(msg);dos.flush();//3、获取消息msg =dis.readUTF();System.out.println(msg);}dos.close();dis.close();client.close();}
}


多线程:使得客户和客户各自是一个线程

手写聊天室_OOP封装版

解决 1、代码不好维护
2、客户端读写没有分开 必须先写后读
封装起来
读写分开
例5:
TMultiChat.java

package com.sxt.chat03;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;/*** 在线聊天室: 服务器* 目标: 封装使用多线程实现多个客户可以正常收发多条消息 * 问题: * 1、代码不好维护* 2、客户端读写没有分开 必须先写后读*/
public class TMultiChat {public static void main(String[] args) throws IOException {System.out.println("-----Server-----");// 1、指定端口 使用ServerSocket创建服务器ServerSocket server =new ServerSocket(8888);// 2、阻塞式等待连接 acceptwhile(true) {Socket  client =server.accept(); System.out.println("一个客户端建立了连接");new Thread(new Channel(client)).start();            }       }//一个客户代表一个Channelstatic class Channel implements Runnable{private DataInputStream dis;private DataOutputStream dos;private Socket  client;         private boolean isRunning;public Channel(Socket  client) {this.client = client;try {dis = new DataInputStream(client.getInputStream());dos =new DataOutputStream(client.getOutputStream());isRunning =true;} catch (IOException e) {System.out.println("---1------");release();                   }           }//接收消息private String receive() {String msg ="";try {msg =dis.readUTF();} catch (IOException e) {System.out.println("---2------");//服务器端的接收release();}return msg;}//发送消息private void send(String msg) {try {dos.writeUTF(msg);dos.flush();} catch (IOException e) {System.out.println("---3------");//服务器端的发送release();}}//释放资源private void release() {this.isRunning = false;SxtUtils.close(dis,dos,client);}@Overridepublic void run() {while(isRunning) {String msg = receive() ;if(!msg.equals("")) {send(msg);}}}}
}

TMultiClient.java

package com.sxt.chat03;import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;/*** 在线聊天室: 客户端* 目标: 封装使用多线程实现多个客户可以正常收发多条消息 */
public class TMultiClient {public static void main(String[] args) throws UnknownHostException, IOException {System.out.println("-----Client-----");//1、建立连接: 使用Socket创建客户端 +服务的地址和端口Socket client =new Socket("localhost",8888);//2、客户端发送消息new Thread(new Send(client)).start();  new Thread(new Receive(client)).start();}
}

Send.java

package com.sxt.chat03;import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;/*** 使用多线程封装:发送端* 1、发送消息* 2、从控制台获取消息* 3、释放资源* 4、重写run*/
public class Send implements Runnable {private BufferedReader console ;private DataOutputStream dos;private Socket client;private boolean isRunning;public Send(Socket client) {this.client =client;console =new BufferedReader(new InputStreamReader(System.in));this.isRunning = true;try {dos =new DataOutputStream(client.getOutputStream());} catch (IOException e) {System.out.println("==1==");this.release();}    }@Overridepublic void run() {while(isRunning) {String msg = getStrFromConsole();if(!msg.equals("")) {send(msg);}}}  //发送消息private void send(String msg) {try {dos.writeUTF(msg);dos.flush();} catch (IOException e) {System.out.println(e);System.out.println("===3==");//客户端的发送release();}}/*** 从控制台获取消息* @return*/private String getStrFromConsole() {try {return  console.readLine();} catch (IOException e) {e.printStackTrace();}return "";}//释放资源private void release() {this.isRunning = false;SxtUtils.close(dos,client);}}

Receive.java

package com.sxt.chat03;import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;/*** 使用多线程封装:接收端
*  1、接收消息* 2、释放资源* 3、重写run*/
public class Receive implements Runnable {private DataInputStream dis ;private Socket client;private boolean isRunning;public Receive(Socket client) {this.client = client;this.isRunning = true;try {dis =new DataInputStream(client.getInputStream());} catch (IOException e) {System.out.println("====2=====");release();}}//接收消息private String receive() {String msg ="";try {msg =dis.readUTF();} catch (IOException e) {System.out.println("====4====");//客户端的 接收release();}return msg;}@Overridepublic void run() {     while(isRunning) {String msg =receive();if(!msg.equals("")) {System.out.println(msg);}}}//释放资源private void release() {this.isRunning = false;SxtUtils.close(dis,client);}}

SxtUtils.java

package com.sxt.chat03;import java.io.Closeable;/*** 工具类*/
public class SxtUtils {/*** 释放资源*/public static void close(Closeable... targets ) {for(Closeable target:targets) {try {if(null!=target) {target.close();}}catch(Exception e) {}}}
}


自己和自己聊天,各自之间不受影响
封装的魅力
任何一个客户端与服务器之间自言自语

手写聊天室_群聊过渡版

客户端发送到服务器一个消息,那么服务器就发送给所有的容器客户端
Chat.java

package com.sxt.chat04;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.CopyOnWriteArrayList;/*** 在线聊天室: 服务器* 目标: 加入容器实现群聊*/
public class Chat {private static CopyOnWriteArrayList<Channel> all =new CopyOnWriteArrayList<Channel>();//一边写一边遍历public static void main(String[] args) throws IOException {System.out.println("-----Server-----");// 1、指定端口 使用ServerSocket创建服务器ServerSocket server =new ServerSocket(8888);// 2、阻塞式等待连接 acceptwhile(true) {//多个 客户端Socket  client =server.accept(); System.out.println("一个客户端建立了连接");Channel c =new Channel(client);//来一个客户端我们就丢一个到容器all.add(c); //管理所有的成员new Thread(c).start();          }       }//一个客户代表一个Channelstatic class Channel implements Runnable{//之前都是只有发给自己的方法,现在把补上发给其他人的方法private DataInputStream dis;private DataOutputStream dos;private Socket  client;         private boolean isRunning;private String name;public Channel(Socket  client) {this.client = client;try {dis = new DataInputStream(client.getInputStream());dos =new DataOutputStream(client.getOutputStream());isRunning =true;//获取名称this.name =receive();//欢迎你的到来this.send("欢迎你的到来");sendOthers(this.name+"来了shsxt聊天室",true);} catch (IOException e) {System.out.println("---1------");release();                  }           }//接收消息private String receive() {String msg ="";try {msg =dis.readUTF();} catch (IOException e) {System.out.println("---2------");release();}return msg;}//发送消息private void send(String msg) {try {dos.writeUTF(msg);dos.flush();} catch (IOException e) {System.out.println("---3------");release();}}/*** 群聊:获取自己的消息,发给其他人* @param msg*/private void sendOthers(String msg,boolean isSys) {//调用其他人的sendfor(Channel other: all) {if(other==this) { //自己continue;}if(!isSys) {other.send(this.name +"对所有人说:"+msg);//群聊消息}else {other.send(msg); //系统消息}}}//释放资源private void release() {this.isRunning = false;SxtUtils.close(dis,dos,client);//退出all.remove(this);sendOthers(this.name+"离开大家庭...",true);}@Overridepublic void run() {while(isRunning) {String msg = receive() ;if(!msg.equals("")) {//send(msg);sendOthers(msg,false);}}}}
}

Client.java

package com.sxt.chat04;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;/*** 在线聊天室: 客户端* 目标: 加入容器实现群聊*/
public class Client {public static void main(String[] args) throws UnknownHostException, IOException {System.out.println("-----Client-----");BufferedReader br =new BufferedReader(new InputStreamReader(System.in));System.out.println("请输入用户名:");String name =br.readLine();//1、建立连接: 使用Socket创建客户端 +服务的地址和端口Socket client =new Socket("localhost",8888);//2、客户端发送消息new Thread(new Send(client,name)).start();  new Thread(new Receive(client)).start();}
}

Send.java

package com.sxt.chat04;import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;/*** 使用多线程封装:发送端* 1、发送消息* 2、从控制台获取消息* 3、释放资源* 4、重写run*/
public class Send implements Runnable {private BufferedReader console ;private DataOutputStream dos;private Socket client;private boolean isRunning;private String name;public Send(Socket client,String name) {this.client =client;console =new BufferedReader(new InputStreamReader(System.in));this.isRunning = true;this.name = name;try {dos =new DataOutputStream(client.getOutputStream());//发送名称send(name);} catch (IOException e) {System.out.println("==1==");this.release();} }@Overridepublic void run() {while(isRunning) {String msg = getStrFromConsole();if(!msg.equals("")) {send(msg);}}}  //发送消息private void send(String msg) {try {dos.writeUTF(msg);dos.flush();} catch (IOException e) {System.out.println(e);System.out.println("===3==");release();}}/*** 从控制台获取消息* @return*/private String getStrFromConsole() {try {return  console.readLine();} catch (IOException e) {e.printStackTrace();}return "";}//释放资源private void release() {this.isRunning = false;SxtUtils.close(dos,client);}}

Receive.java

package com.sxt.chat03;import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;/*** 使用多线程封装:接收端
*  1、接收消息* 2、释放资源* 3、重写run*/
public class Receive implements Runnable {private DataInputStream dis ;private Socket client;private boolean isRunning;public Receive(Socket client) {this.client = client;this.isRunning = true;try {dis =new DataInputStream(client.getInputStream());} catch (IOException e) {System.out.println("====2=====");release();}}//接收消息private String receive() {String msg ="";try {msg =dis.readUTF();} catch (IOException e) {System.out.println("====4====");//客户端的 接收release();}return msg;}@Overridepublic void run() {     while(isRunning) {String msg =receive();if(!msg.equals("")) {System.out.println(msg);}}}//释放资源private void release() {this.isRunning = false;SxtUtils.close(dis,client);}}

SxtUtils.java

package com.sxt.chat03;import java.io.Closeable;/*** 工具类*/
public class SxtUtils {/*** 释放资源*/public static void close(Closeable... targets ) {for(Closeable target:targets) {try {if(null!=target) {target.close();}}catch(Exception e) {}}}
}


输入各自客户端的名字以后,才建立连接

手写聊天室_私聊终极版

Chat.java

package com.sxt.chat05;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.CopyOnWriteArrayList;/*** 在线聊天室: 服务器* 目标: 私聊*/
public class Chat {private static CopyOnWriteArrayList<Channel> all =new CopyOnWriteArrayList<Channel>();public static void main(String[] args) throws IOException {System.out.println("-----Server-----");// 1、指定端口 使用ServerSocket创建服务器ServerSocket server =new ServerSocket(8888);// 2、阻塞式等待连接 acceptwhile(true) {Socket  client =server.accept(); System.out.println("一个客户端建立了连接");Channel c =new Channel(client);all.add(c); //管理所有的成员new Thread(c).start();            }       }//一个客户代表一个Channelstatic class Channel implements Runnable{private DataInputStream dis;private DataOutputStream dos;private Socket  client;         private boolean isRunning;private String name;public Channel(Socket  client) {this.client = client;try {dis = new DataInputStream(client.getInputStream());dos =new DataOutputStream(client.getOutputStream());isRunning =true;//获取名称this.name =receive();//欢迎你的到来this.send("欢迎你的到来");sendOthers(this.name+"来了shsxt聊天室",true);} catch (IOException e) {System.out.println("---1------");release();                  }           }//接收消息private String receive() {String msg ="";try {msg =dis.readUTF();} catch (IOException e) {System.out.println("---2------");release();}return msg;}//发送消息private void send(String msg) {try {dos.writeUTF(msg);dos.flush();} catch (IOException e) {System.out.println("---3------");release();}}/*** 群聊:获取自己的消息,发给其他人* 私聊: 约定数据格式: @xxx:msg* @param msg*/private void sendOthers(String msg,boolean isSys) {boolean isPrivate = msg.startsWith("@");if(isPrivate) { //私聊int idx =msg.indexOf(":");//获取目标和数据String targetName = msg.substring(1,idx);msg = msg.substring(idx+1);for(Channel other: all) {if(other.name.equals(targetName)) {//目标other.send(this.name +"悄悄地对您说:"+msg);break;}}}else {                for(Channel other: all) {if(other==this) { //自己continue;}if(!isSys) {other.send(this.name +"对所有人说:"+msg);//群聊消息}else {other.send(msg); //系统消息}}}}//释放资源private void release() {this.isRunning = false;SxtUtils.close(dis,dos,client);//退出all.remove(this);sendOthers(this.name+"离开大家庭...",true);}@Overridepublic void run() {while(isRunning) {String msg = receive() ;if(!msg.equals("")) {//send(msg);sendOthers(msg,false);}}}}
}

Client.java

package com.sxt.chat05;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;/*** 在线聊天室: 客户端* 目标: 私聊*/
public class Client {public static void main(String[] args) throws UnknownHostException, IOException {System.out.println("-----Client-----");BufferedReader br =new BufferedReader(new InputStreamReader(System.in));System.out.println("请输入用户名:");String name =br.readLine();//1、建立连接: 使用Socket创建客户端 +服务的地址和端口Socket client =new Socket("localhost",8888);//2、客户端发送消息new Thread(new Send(client,name)).start();  new Thread(new Receive(client)).start();}
}

Receive.java

package com.sxt.chat05;import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;/*** 使用多线程封装:接收端
*  1、接收消息* 2、释放资源* 3、重写run*/
public class Receive implements Runnable {private DataInputStream dis ;private Socket client;private boolean isRunning;public Receive(Socket client) {this.client = client;this.isRunning = true;try {dis =new DataInputStream(client.getInputStream());} catch (IOException e) {System.out.println("====2=====");release();}}//接收消息private String receive() {String msg ="";try {msg =dis.readUTF();} catch (IOException e) {System.out.println("====4====");release();}return msg;}@Overridepublic void run() {      while(isRunning) {String msg =receive();if(!msg.equals("")) {System.out.println(msg);}}}//释放资源private void release() {this.isRunning = false;SxtUtils.close(dis,client);}}

Send.java

package com.sxt.chat05;import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;/*** 使用多线程封装:发送端* 1、发送消息* 2、从控制台获取消息* 3、释放资源* 4、重写run*/
public class Send implements Runnable {private BufferedReader console ;private DataOutputStream dos;private Socket client;private boolean isRunning;private String name;public Send(Socket client,String name) {this.client =client;console =new BufferedReader(new InputStreamReader(System.in));this.isRunning = true;this.name = name;try {dos =new DataOutputStream(client.getOutputStream());//发送名称send(name);} catch (IOException e) {System.out.println("==1==");this.release();} }@Overridepublic void run() {while(isRunning) {String msg = getStrFromConsole();if(!msg.equals("")) {send(msg);}}}  //发送消息private void send(String msg) {try {dos.writeUTF(msg);dos.flush();} catch (IOException e) {System.out.println(e);System.out.println("===3==");release();}}/*** 从控制台获取消息* @return*/private String getStrFromConsole() {try {return  console.readLine();} catch (IOException e) {e.printStackTrace();}return "";}//释放资源private void release() {this.isRunning = false;SxtUtils.close(dos,client);}}

SxtUtils.java

package com.sxt.chat05;import java.io.Closeable;/*** 工具类* */
public class SxtUtils {/*** 释放资源*/public static void close(Closeable... targets ) {for(Closeable target:targets) {try {if(null!=target) {target.close();}}catch(Exception e) {}}}
}

12.2.3 UDP协议

基于TCP协议可以建立稳定连接的点对点的通信。这种通信方式实时、快速、安全性高,但是很占用系统的资源。

在网络传输方式上,还有另一种基于UDP协议的通信方式,称为数据报通信方式。在这种方式中,每个数据发送单元被统一封装成数据报包的方式,发送方将数据报包发送到网络中,数据报包在网络中去寻找它的目的地。

UDP基本步骤


例1:
UdpClient.java

package com.sxt.udp;import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;/*** 基本流程: 发送端* 1、使用DatagramSocket  指定端口 创建发送端* 2、准备数据 一定转成字节数组* 3、 封装成DatagramPacket 包裹,需要指定目的地* 4、发送包裹send​(DatagramPacket p) * * 5、释放资源*/
public class UdpClient {public static void main(String[] args) throws Exception {System.out.println("发送方启动中.....");// 1、使用DatagramSocket  指定端口 创建发送端DatagramSocket client =new DatagramSocket(8888);//2、准备数据 一定转成字节数组String data = "上海尚学堂";byte[] datas = data.getBytes();//3、 封装成DatagramPacket 包裹,需要指定目的地DatagramPacket packet =new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",6666));//4、发送包裹send​(DatagramPacket p) * client.send(packet);// 5、释放资源client.close();}}

UdpServer.java

package com.sxt.udp;import java.net.DatagramPacket;
import java.net.DatagramSocket;/*** 基本流程: 接收端* Address already in use: Cannot bind  同一个协议下端口不允许冲突* 1、使用DatagramSocket  指定端口 创建接收端* 2、准备容器 封装成DatagramPacket 包裹* 3、阻塞式接收包裹receive​(DatagramPacket p)* 4、分析数据*    byte[]  getData​()*                getLength​()* 5、释放资源*/
public class UdpServer {public static void main(String[] args) throws Exception {System.out.println("接收方启动中.....");// 1、使用DatagramSocket  指定端口 创建接收端DatagramSocket server =new DatagramSocket(6666);// 2、准备容器 封装成DatagramPacket 包裹byte[] container =new byte[1024*60];DatagramPacket packet = new DatagramPacket(container,0,container.length);// 3、阻塞式接收包裹receive​(DatagramPacket p)server.receive(packet); //阻塞式// 4、分析数据//    byte[]  getData​()//                getLength​()byte[]  datas =packet.getData();int len = packet.getLength();System.out.println(new String(datas,0,len));// 5、释放资源server.close();}}

UDP上传文件

例2:
UdpTypeClient.java

package com.sxt.udp;import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;/*** 基本类型: 发送端* 1、使用DatagramSocket  指定端口 创建发送端* 2、将基本类型  转成字节数组* 3、 封装成DatagramPacket 包裹,需要指定目的地* 4、发送包裹send​(DatagramPacket p) * * 5、释放资源*/
public class UdpTypeClient {public static void main(String[] args) throws Exception {System.out.println("发送方启动中.....");// 1、使用DatagramSocket  指定端口 创建发送端DatagramSocket client =new DatagramSocket(8888);//2、准备数据 一定转成字节数组//写出ByteArrayOutputStream baos =new ByteArrayOutputStream();DataOutputStream dos =new DataOutputStream(new BufferedOutputStream(baos));//操作数据类型 +数据dos.writeUTF("编码辛酸泪");dos.writeInt(18);dos.writeBoolean(false);dos.writeChar('a');dos.flush();byte[] datas =baos.toByteArray();  //3、 封装成DatagramPacket 包裹,需要指定目的地DatagramPacket packet =new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",6666));//4、发送包裹send​(DatagramPacket p) * client.send(packet);// 5、释放资源client.close();}}

UdpTypeServer.java

package com.sxt.udp;import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;/*** 基本类型: 接收端* Address already in use: Cannot bind  同一个协议下端口不允许冲突* 1、使用DatagramSocket  指定端口 创建接收端* 2、准备容器 封装成DatagramPacket 包裹* 3、阻塞式接收包裹receive​(DatagramPacket p)* 4、分析数据    将字节数组还原为对应的类型*    byte[]  getData​()*                getLength​()* 5、释放资源*/
public class UdpTypeServer {public static void main(String[] args) throws Exception {System.out.println("接收方启动中.....");// 1、使用DatagramSocket  指定端口 创建接收端DatagramSocket server =new DatagramSocket(6666);// 2、准备容器 封装成DatagramPacket 包裹byte[] container =new byte[1024*60];DatagramPacket packet = new DatagramPacket(container,0,container.length);// 3、阻塞式接收包裹receive​(DatagramPacket p)server.receive(packet); //阻塞式// 4、分析数据    将字节数组还原为对应的类型//    byte[]  getData​()//                getLength​()byte[]  datas =packet.getData();int len = packet.getLength();       DataInputStream dis =new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(datas)));//顺序与写出一致String msg = dis.readUTF(); int age = dis.readInt();boolean flag = dis.readBoolean();char ch = dis.readChar();System.out.println(msg+"-->"+flag);// 5、释放资源server.close();}}

例3:
Employee.java

package com.sxt.udp;
//javabean 封装数据
public class Employee implements java.io.Serializable{private transient String name; //该数据不需要序列化private double salary;public Employee() {}public Employee(String name, double salary) {this.name = name;this.salary = salary;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getSalary() {return salary;}public void setSalary(double salary) {this.salary = salary;}}

UdpObjClient.java

package com.sxt.udp;import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.util.Date;/***  引用类型: 发送端* 1、使用DatagramSocket  指定端口 创建发送端* 2、将基本类型  转成字节数组* 3、 封装成DatagramPacket 包裹,需要指定目的地* 4、发送包裹send​(DatagramPacket p) * * 5、释放资源*/
public class UdpObjClient {public static void main(String[] args) throws Exception {System.out.println("发送方启动中.....");// 1、使用DatagramSocket  指定端口 创建发送端DatagramSocket client =new DatagramSocket(8888);//2、准备数据 一定转成字节数组//写出ByteArrayOutputStream baos =new ByteArrayOutputStream();ObjectOutputStream oos =new ObjectOutputStream(new BufferedOutputStream(baos));//操作数据类型 +数据oos.writeUTF("编码辛酸泪");oos.writeInt(18);oos.writeBoolean(false);oos.writeChar('a');//对象oos.writeObject("谁解其中味");oos.writeObject(new Date());Employee emp =new Employee("马云",400);oos.writeObject(emp);oos.flush();byte[] datas =baos.toByteArray();   //3、 封装成DatagramPacket 包裹,需要指定目的地DatagramPacket packet =new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",6666));//4、发送包裹send​(DatagramPacket p) * client.send(packet);// 5、释放资源client.close();}}

UdpObjServer.java

package com.sxt.udp;import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.Date;/*** 引用类型: 接收端* Address already in use: Cannot bind  同一个协议下端口不允许冲突* 1、使用DatagramSocket  指定端口 创建接收端* 2、准备容器 封装成DatagramPacket 包裹* 3、阻塞式接收包裹receive​(DatagramPacket p)* 4、分析数据    将字节数组还原为对应的类型*    byte[]  getData​()*                getLength​()* 5、释放资源*/
public class UdpObjServer {public static void main(String[] args) throws Exception {System.out.println("接收方启动中.....");// 1、使用DatagramSocket  指定端口 创建接收端DatagramSocket server =new DatagramSocket(6666);// 2、准备容器 封装成DatagramPacket 包裹byte[] container =new byte[1024*60];DatagramPacket packet = new DatagramPacket(container,0,container.length);// 3、阻塞式接收包裹receive​(DatagramPacket p)server.receive(packet); //阻塞式// 4、分析数据    将字节数组还原为对应的类型//    byte[]  getData​()//                getLength​()byte[]  datas =packet.getData();int len = packet.getLength();        //读取 -->反序列化ObjectInputStream ois =new ObjectInputStream(new BufferedInputStream(new ByteArrayInputStream(datas)));//顺序与写出一致String msg = ois.readUTF(); int age = ois.readInt();boolean flag = ois.readBoolean();char ch = ois.readChar();System.out.println(flag);//对象的数据还原  Object str = ois.readObject();Object date = ois.readObject();Object employee = ois.readObject();if(str instanceof String) {String strObj = (String) str;System.out.println(strObj);}if(date instanceof Date) {Date dateObj = (Date) date;System.out.println(dateObj);}if(employee instanceof Employee) {Employee empObj = (Employee) employee;System.out.println(empObj.getName()+"-->"+empObj.getSalary());}// 5、释放资源server.close();}}

例4:
IOUtils.java

package com.sxt.udp;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;/***1、 图片读取到字节数组*2、 字节数组写出到文件*  @author 裴新**/
public class IOUtils {/*** 1、图片读取到字节数组* 1)、图片到程序  FileInputStream* 2)、程序到字节数组   ByteArrayOutputStream*/public static byte[] fileToByteArray(String filePath) {//1、创建源与目的地File src = new File(filePath);byte[] dest =null;//2、选择流InputStream  is =null;ByteArrayOutputStream baos =null;try {is =new FileInputStream(src);baos = new ByteArrayOutputStream();//3、操作 (分段读取)byte[] flush = new byte[1024*10]; //缓冲容器int len = -1; //接收长度while((len=is.read(flush))!=-1) {baos.write(flush,0,len);         //写出到字节数组中         }       baos.flush();return baos.toByteArray();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {//4、释放资源try {if(null!=is) {is.close();}} catch (IOException e) {e.printStackTrace();}}return null;        }/*** 2、字节数组写出到图片* 1)、字节数组到程序 ByteArrayInputStream* 2)、程序到文件 FileOutputStream*/public static void byteArrayToFile(byte[] src,String filePath) {//1、创建源File dest = new File(filePath);//2、选择流InputStream  is =null;OutputStream os =null;try {is =new ByteArrayInputStream(src);os = new FileOutputStream(dest);//3、操作 (分段读取)byte[] flush = new byte[5]; //缓冲容器int len = -1; //接收长度while((len=is.read(flush))!=-1) {os.write(flush,0,len);          //写出到文件 }       os.flush();} catch (IOException e) {e.printStackTrace();}finally {//4、释放资源try {if (null != os) {os.close();} } catch (Exception e) {}}}
}

UdpFileClient.java

package com.sxt.udp;import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;/***  文件上传: 发送端* 1、使用DatagramSocket  指定端口 创建发送端* 2、将基本类型  转成字节数组* 3、 封装成DatagramPacket 包裹,需要指定目的地* 4、发送包裹send​(DatagramPacket p) * * 5、释放资源*/
public class UdpFileClient {public static void main(String[] args) throws Exception {System.out.println("发送方启动中.....");// 1、使用DatagramSocket  指定端口 创建发送端DatagramSocket client =new DatagramSocket(8888);//2、准备数据 一定转成字节数组byte[] datas =IOUtils.fileToByteArray("src/logo.png");       //3、 封装成DatagramPacket 包裹,需要指定目的地DatagramPacket packet =new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",6666));//4、发送包裹send​(DatagramPacket p) * client.send(packet);// 5、释放资源client.close();}}

UdpFileServer.java

package com.sxt.udp;import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.Date;/*** 文件存储: 接收端* Address already in use: Cannot bind  同一个协议下端口不允许冲突* 1、使用DatagramSocket  指定端口 创建接收端* 2、准备容器 封装成DatagramPacket 包裹* 3、阻塞式接收包裹receive​(DatagramPacket p)* 4、分析数据    将字节数组还原为对应的类型*    byte[]  getData​()*                getLength​()* 5、释放资源*/
public class UdpFileServer {public static void main(String[] args) throws Exception {System.out.println("接收方启动中.....");// 1、使用DatagramSocket  指定端口 创建接收端DatagramSocket server =new DatagramSocket(6666);// 2、准备容器 封装成DatagramPacket 包裹byte[] container =new byte[1024*60];DatagramPacket packet = new DatagramPacket(container,0,container.length);// 3、阻塞式接收包裹receive​(DatagramPacket p)server.receive(packet); //阻塞式// 4、分析数据    将字节数组还原为对应的类型//    byte[]  getData​()//                getLength​()byte[]  datas =packet.getData();int len = packet.getLength();       IOUtils.byteArrayToFile(datas, "src/copy.png");       // 5、释放资源server.close();}
}

UDP案例在线咨询


可以多次交流,加入多线程
例5:
UdpTalkClient.java

package com.sxt.udp;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;/*** 多次交流: 发送端* 1、使用DatagramSocket  指定端口 创建发送端* 2、准备数据 一定转成字节数组* 3、 封装成DatagramPacket 包裹,需要指定目的地* 4、发送包裹send​(DatagramPacket p) * * 5、释放资源*/
public class UdpTalkClient {public static void main(String[] args) throws Exception {System.out.println("发送方启动中.....");// 1、使用DatagramSocket  指定端口 创建发送端DatagramSocket client =new DatagramSocket(8888);//2、准备数据 一定转成字节数组BufferedReader reader =new BufferedReader(new InputStreamReader(System.in));//控制台输入while(true) {String data = reader.readLine();byte[] datas = data.getBytes();//3、 封装成DatagramPacket 包裹,需要指定目的地DatagramPacket packet =new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",6666));//4、发送包裹send​(DatagramPacket p) * client.send(packet);if(data.equals("bye")) {break;}}// 5、释放资源client.close();}}

UdpTalkServer.java

package com.sxt.udp;import java.net.DatagramPacket;
import java.net.DatagramSocket;/*** 多次交流: 接收端* Address already in use: Cannot bind  同一个协议下端口不允许冲突* 1、使用DatagramSocket  指定端口 创建接收端* 2、准备容器 封装成DatagramPacket 包裹* 3、阻塞式接收包裹receive​(DatagramPacket p)* 4、分析数据*    byte[]  getData​()*                getLength​()* 5、释放资源*/
public class UdpTalkServer {public static void main(String[] args) throws Exception {System.out.println("接收方启动中.....");// 1、使用DatagramSocket  指定端口 创建接收端DatagramSocket server =new DatagramSocket(6666);while(true) {// 2、准备容器 封装成DatagramPacket 包裹byte[] container =new byte[1024*60];DatagramPacket packet = new DatagramPacket(container,0,container.length);// 3、阻塞式接收包裹receive​(DatagramPacket p)server.receive(packet); //阻塞式// 4、分析数据//    byte[]  getData​()//                getLength​()byte[]  datas =packet.getData();int len = packet.getLength();String data=new String(datas,0,len);System.out.println(data);if(data.equals("bye")) {break;}}// 5、释放资源server.close();}}

例6:
加入多线程
TalkSend.java

package com.sxt.udp;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;/*** 发送端: 使用面向对象封装*/
public class TalkSend implements Runnable {private DatagramSocket client ;private BufferedReader reader;private String toIP ;//对方的IPprivate int toPort ;//对方的端口public TalkSend(int port,String toIP,int toPort) {this.toIP = toIP;this.toPort=toPort;try {client=new DatagramSocket(port);reader =new BufferedReader(new InputStreamReader(System.in));} catch (SocketException e) {e.printStackTrace();}}@Overridepublic void run() {while(true) {String data;try {data = reader.readLine();byte[] datas = data.getBytes();//3、 封装成DatagramPacket 包裹,需要指定目的地DatagramPacket packet =new DatagramPacket(datas,0,datas.length,new InetSocketAddress(this.toIP,this.toPort));//4、发送包裹send​(DatagramPacket p) * client.send(packet);if(data.equals("bye")) {break;}} catch (IOException e) {e.printStackTrace();}}// 5、释放资源client.close();}}

TalkReceive.java

package com.sxt.udp;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;/*** 接收端: 使用面向对象封装*/
public class TalkReceive implements Runnable {private DatagramSocket server ;private String from ;public TalkReceive(int port,String from) {this.from = from ;try {server=new DatagramSocket(port);} catch (SocketException e) {e.printStackTrace();}}@Overridepublic void run() {while(true) {// 2、准备容器 封装成DatagramPacket 包裹byte[] container =new byte[1024*60];DatagramPacket packet = new DatagramPacket(container,0,container.length);// 3、阻塞式接收包裹receive​(DatagramPacket p)try {server.receive(packet);//阻塞式// 4、分析数据byte[]  datas =packet.getData();int len = packet.getLength();String data=new String(datas,0,len);System.out.println(from+":"+data);if(data.equals("bye")) {break;}} catch (IOException e) {e.printStackTrace();} }// 5、释放资源server.close();}}

双向交流
TalkStudent.java

package com.sxt.udp;
/*** 加入多线程,实现双向交流 模拟在线咨询* * @author 裴新 QQ:3401997271**/
public class TalkStudent {public static void main(String[] args) {new Thread(new TalkSend(7777,"localhost",9999)).start(); //发送       new Thread(new TalkReceive(8888,"老师")).start(); //接收}
}

TalkTeacher.java

package com.sxt.udp;
/*** 加入多线程,实现双向交流 模拟在线咨询*/
public class TalkTeacher {public static void main(String[] args) {new Thread(new TalkReceive(9999,"学生")).start(); //接收new Thread(new TalkSend(5555,"localhost",8888)).start(); //发送}
}



12.3 Java网络编程

Java为了可移植性,不允许直接调用操作系统,而是由java.net包来提供网络功能。Java虚拟机负责提供与操作系统的实际连接。下面我们来介绍几个java.net包中的常用的类。

12.3.1 InetAddress

作用:封装计算机的IP地址和DNS(没有端口信息)。
注:DNS是Domain Name System,域名系统。
特点:这个类没有构造方法。如果要得到对象,只能通过静态方法:getLocalHost()、getByName()、 getAllByName()、 getAddress()、getHostName()。

【示例12-1】使用getLocalHost方法创建InetAddress对象

import java.net.InetAddress;
import java.net.UnknownHostException;
public class Test1 {public static void main(String[] args) throws UnknownHostException {InetAddress addr = InetAddress.getLocalHost();//返回IP地址:192.168.1.110System.out.println(addr.getHostAddress()); //输出计算机名:gaoqiSystem.out.println(addr.getHostName());     }
}

【示例12-2】根据域名得到InetAddress对象

import java.net.InetAddress;
import java.net.UnknownHostException;
public class Test2 {public static void main(String[] args) throws UnknownHostException {InetAddress addr = InetAddress.getByName("www.sxt.cn");// 返回 sxt服务器的IP:59.110.14.7System.out.println(addr.getHostAddress());// 输出:www.sxt.cnSystem.out.println(addr.getHostName());}
}

【示例12-3】根据IP得到InetAddress对象

import java.net.InetAddress;
import java.net.UnknownHostException;
public class Test3 {public static void main(String[] args) throws UnknownHostException {InetAddress addr = InetAddress.getByName("59.110.14.7");// 返回sxt服务器的IP:59.110.14.7System.out.println(addr.getHostAddress());/** 输出ip而不是域名。如果这个IP地址不存在或DNS服务器不允许进行IP地址* 和域名的映射,getHostName方法就直接返回这个IP地址。*/System.out.println(addr.getHostName());}
}

12.3.2 InetSocketAddress

作用:包含IP和端口信息,常用于Socket通信。此类实现 IP 套接字地址(IP 地址 + 端口号),不依赖任何协议。

【示例12-4】InetSocketAddress的使用

import java.net.InetSocketAddress;
public class Test4 {public static void main(String[] args) {InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 8080);InetSocketAddress socketAddress2 = new InetSocketAddress("localhost", 9000);System.out.println(socketAddress.getHostName());System.out.println(socketAddress2.getAddress());}
}

12.3.3 URL类

IP地址唯一标识了Internet上的计算机,而URL则标识了这些计算机上的资源。类 URL 代表一个统一资源定位符,它是指向互联网“资源”的指针。资源可以是简单的文件或目录,也可以是对更为复杂的对象的引用,例如对数据库或搜索引擎的查询。

为了方便程序员编程,JDK中提供了URL类,该类的全名是java.net.URL,有了这样一个类,就可以使用它的各种方法来对URL对象进行分割、合并等处理。

【示例12-5】URL类的使用

import java.net.MalformedURLException;
import java.net.URL;
public class Test5 {public static void main(String[] args) throws MalformedURLException {URL u = new URL("http://www.google.cn:80/webhp#aa?canhu=33");System.out.println("获取与此url关联的协议的默认端口:" + u.getDefaultPort());System.out.println("getFile:" + u.getFile()); // 端口号后面的内容System.out.println("主机名:" + u.getHost()); // www.google.cnSystem.out.println("路径:" + u.getPath()); // 端口号后,参数前的内容// 如果www.google.cn:80则返回80.否则返回-1System.out.println("端口:" + u.getPort()); System.out.println("协议:" + u.getProtocol());System.out.println("参数部分:" + u.getQuery());System.out.println("锚点:" + u.getRef());URL u1 = new URL("http://www.abc.com/aa/");URL u2 = new URL(u, "2.html"); // 相对路径构建url对象System.out.println(u2.toString()); // http://www.abc.com/aa/2.html}
}

【示例12-6】最简单的网络爬虫

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;public class Test6 {public static void main(String[] args) {basicSpider();}//网络爬虫static void basicSpider() {URL url = null;InputStream is = null;BufferedReader br = null;StringBuilder sb = new StringBuilder();String temp = "";try {url = new URL("http://www.baidu.com");is = url.openStream();br = new BufferedReader(new InputStreamReader(is));/* * 这样就可以将网络内容下载到本地机器。* 然后进行数据分析,建立索引。这也是搜索引擎的第一步。*/while ((temp = br.readLine()) != null) {sb.append(temp);}System.out.println(sb);} catch (MalformedURLException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {br.close();} catch (IOException e) {e.printStackTrace();}try {is.close();} catch (IOException e) {e.printStackTrace();}}}
}

12.3.4 基于TCP协议的Socket编程和通信

在网络通讯中,第一次主动发起通讯的程序被称作客户端(Client)程序,简称客户端,而在第一次通讯中等待连接的程序被称作服务器端(Server)程序,简称服务器。一旦通讯建立,则客户端和服务器端完全一样,没有本质的区别。

“请求-响应”模式:
1.Socket类:发送TCP消息。
2.ServerSocket类:创建服务器。

套接字是一种进程间的数据交换机制。这些进程既可以在同一机器上,也可以在通过网络连接的不同机器上。换句话说,套接字起到通信端点的作用。单个套接字是一个端点,而一对套接字则构成一个双向通信信道,使非关联进程可以在本地或通过网络进行数据交换。一旦建立套接字连接,数据即可在相同或不同的系统中双向或单向发送,直到其中一个端点关闭连接。套接字与主机地址和端口地址相关联。主机地址就是客户端或服务器程序所在的主机的IP地址。端口地址是指客户端或服务器程序使用的主机的通信端口。

在客户端和服务器中,分别创建独立的Socket,并通过Socket的属性,将两个Socket进行连接,这样,客户端和服务器通过套接字所建立的连接使用输入输出流进行通信。

TCP/IP套接字是最可靠的双向流协议,使用TCP/IP可以发送任意数量的数据。

实际上,套接字只是计算机上已编号的端口。如果发送方和接收方计算机确定好端口,他们就可以通信了。

如图12-6所示为客户端与服务器端的通信关系图:

TCP/IP通信连接的简单过程:
位于A计算机上的TCP/IP软件向B计算机发送包含端口号的消息,B计算机的TCP/IP软件接收该消息,并进行检查,查看是否有它知道的程序正在该端口上接收消息。如果有,他就将该消息交给这个程序。
要使程序有效地运行,就必须有一个客户端和一个服务器。

通过Socket的编程顺序:
1.创建服务器ServerSocket,在创建时,定义ServerSocket的监听端口(在这个端口接收客户端发来的消息)。
2.ServerSocket调用accept()方法,使之处于阻塞状态。
3.创建客户端Socket,并设置服务器的IP及端口。
4.客户端发出连接请求,建立连接。
5.分别取得服务器和客户端Socket的InputStream和OutputStream。
6.利用Socket和ServerSocket进行数据传输。
7.关闭流及Socket。
【示例12-7】TCP:单向通信Socket之服务器端

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;/*** 最简单的服务器端代码* @author Administrator*/
public class BasicSocketServer {public static void main(String[] args) {Socket socket = null;BufferedWriter bw = null;try {// 建立服务器端套接字:指定监听的接口ServerSocket serverSocket = new ServerSocket(8888);System.out.println("服务端建立监听");// 监听,等待客户端请求,并愿意接收连接socket = serverSocket.accept();// 获取socket的输出流,并使用缓冲流进行包装bw = new BufferedWriter(new     OutputStreamWriter(socket.getOutputStream()));// 向客户端发送反馈信息bw.write("hhhh");} catch (IOException e) {e.printStackTrace();} finally {// 关闭流及socket连接if (bw != null) {try {bw.close();} catch (IOException e) {e.printStackTrace();}}if (socket != null) {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}
}

【示例12-8】TCP:单向通信Socket之客户端

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.Socket;
/*** 最简单的Socket客户端* @author Administrator*/
public class BasicSocketClient {public static void main(String[] args) {Socket socket = null;BufferedReader br = null;try {/** 创建Scoket对象:指定要连接的服务器的IP和端口而不是自己机器的* 端口。发送端口是随机的。*/socket = new Socket(InetAddress.getLocalHost(), 8888);//获取scoket的输入流,并使用缓冲流进行包装br = new BufferedReader(new  InputStreamReader(socket.getInputStream()));//接收服务器端发送的信息System.out.println(br.readLine());} catch (Exception e) {e.printStackTrace();} finally {// 关闭流及socket连接if (br != null) {try {br.close();} catch (IOException e) {e.printStackTrace();}}if (socket != null) {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}
}

【示例12-9】TCP:双向通信Socket之服务器端

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args){Socket socket = null;BufferedReader in = null;BufferedWriter out = null;BufferedReader br = null;try {//创建服务器端套接字:指定监听端口ServerSocket server = new ServerSocket(8888);//监听客户端的连接socket = server.accept();//获取socket的输入输出流接收和发送信息in = new BufferedReader(new InputStreamReader(socket.getInputStream()));out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));br = new BufferedReader(new InputStreamReader(System.in));while (true) {//接收客户端发送的信息String str = in.readLine();System.out.println("客户端说:" + str);String str2 = "";//如果客户端发送的是“end”则终止连接 if (str.equals("end")){break;}//否则,发送反馈信息str2 = br.readLine(); // 读到\n为止,因此一定要输入换行符!out.write(str2 + "\n");out.flush();}} catch (IOException e) {e.printStackTrace();} finally {//关闭资源if(in != null){try {in.close();} catch (IOException e) {e.printStackTrace();}}if(out != null){try {out.close();} catch (IOException e) {e.printStackTrace();}}if(br != null){try {br.close();} catch (IOException e) {e.printStackTrace();}}if(socket != null){try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}
}

【示例12-10】TCP:双向通信Socket之客户端

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;public class Client {public static void main(String[] args) {Socket socket = null;BufferedReader in = null;BufferedWriter out = null;BufferedReader wt = null;try {//创建Socket对象,指定服务器端的IP与端口socket = new Socket(InetAddress.getLocalHost(), 8888);//获取scoket的输入输出流接收和发送信息in = new BufferedReader(new InputStreamReader(socket.getInputStream()));out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));wt = new BufferedReader(new InputStreamReader(System.in));while (true) {//发送信息String str = wt.readLine();out.write(str + "\n");out.flush();//如果输入的信息为“end”则终止连接if (str.equals("end")) {break;}//否则,接收并输出服务器端信息System.out.println("服务器端说:" + in.readLine());}} catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {// 关闭资源if (out != null) {try {out.close();} catch (IOException e) {e.printStackTrace();}}if (in != null) {try {in.close();} catch (IOException e) {e.printStackTrace();}}if (wt != null) {try {wt.close();} catch (IOException e) {e.printStackTrace();}}if (socket != null) {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}
}

执行结果如图12-7与图12-8所示


菜鸟雷区
运行时,要先启动服务器端,再启动客户端,才能得到正常的运行效果。
但是,上面这个程序,必须按照安排好的顺序,服务器和客户端一问一答!不够灵活!!可以使用多线程实现更加灵活的双向通讯!!
服务器端:一个线程专门发送消息,一个线程专门接收消息。
客户端:一个线程专门发送消息,一个线程专门接收消息。

【示例12-11】TCP:聊天室之服务器端

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
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 server = null;Socket socket = null;BufferedReader in = null;try {server = new ServerSocket(8888);socket = server.accept();//创建向客户端发送消息的线程,并启动new ServerThread(socket).start();// main线程负责读取客户端发来的信息in = new BufferedReader(new InputStreamReader(socket.getInputStream()));while (true) {String str = in.readLine();System.out.println("客户端说:" + str);}} catch (IOException e) {e.printStackTrace();} finally {try {if (in != null) {in.close();}} catch (IOException e) {e.printStackTrace();}try {if (socket != null) {socket.close();}} catch (IOException e) {e.printStackTrace();}}}
}/*** 专门向客户端发送消息的线程* * @author Administrator**/
class ServerThread extends Thread {Socket ss;BufferedWriter out;BufferedReader br;public ServerThread(Socket ss) {this.ss = ss;try {out = new BufferedWriter(new OutputStreamWriter(ss.getOutputStream()));br = new BufferedReader(new InputStreamReader(System.in));} catch (IOException e) {e.printStackTrace();}}public void run() {try {while (true) {String str2 = br.readLine();out.write(str2 + "\n");out.flush();}} catch (IOException e) {e.printStackTrace();} finally {try {if(out != null){out.close();}} catch (IOException e) {e.printStackTrace();}try {if(br != null){br.close();}} catch (IOException e) {e.printStackTrace();}}}
}

【示例12-12】TCP:聊天室之客户端

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;public class ChatClient {public static void main(String[] args) {Socket socket = null;BufferedReader in = null;try {socket = new Socket(InetAddress.getByName("127.0.1.1"), 8888);// 创建向服务器端发送信息的线程,并启动new ClientThread(socket).start();in = new BufferedReader(new InputStreamReader(socket.getInputStream()));// main线程负责接收服务器发来的信息while (true) {System.out.println("服务器说:" + in.readLine());}} catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {if (socket != null) {socket.close();}} catch (IOException e) {e.printStackTrace();}try {if (in != null) {in.close();}} catch (IOException e) {e.printStackTrace();}}}
}/*** 用于向服务器发送消息* * @author Administrator**/
class ClientThread extends Thread {Socket s;BufferedWriter out;BufferedReader wt;public ClientThread(Socket s) {this.s = s;try {out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));wt = new BufferedReader(new InputStreamReader(System.in));} catch (IOException e) {e.printStackTrace();}}public void run() {try {while (true) {String str = wt.readLine();out.write(str + "\n");out.flush();}} catch (IOException e) {e.printStackTrace();} finally {try {if (wt != null) {wt.close();}} catch (IOException e) {e.printStackTrace();}try {if (out != null) {out.close();}} catch (IOException e) {e.printStackTrace();}}}
}

执行结果如图12-9与图12-10所示:

12.3.5 UDP通讯的实现

▪ DatagramSocket:用于发送或接收数据报包
当服务器要向客户端发送数据时,需要在服务器端产生一个DatagramSocket对象,在客户端产生一个DatagramSocket对象。服务器端的DatagramSocket将DatagramPacket发送到网络上,然后被客户端的DatagramSocket接收。

DatagramSocket有两种常用的构造函数。一种是无需任何参数的,常用于客户端;另一种需要指定端口,常用于服务器端。如下所示:

DatagramSocket() :构造数据报套接字并将其绑定到本地主机上任何可用的端口。
DatagramSocket(int port) :创建数据报套接字并将其绑定到本地主机上的指定端口。

常用方法:
Ø send(DatagramPacket p) :从此套接字发送数据报包。
Ø receive(DatagramPacket p) :从此套接字接收数据报包。
Ø close() :关闭此数据报套接字。

▪ DatagramPacket:数据容器(封包)的作用
此类表示数据报包。 数据报包用来实现封包的功能。
常用方法:
Ø DatagramPacket(byte[] buf, int length) :构造数据报包,用来接收长度为 length 的数据包。
Ø DatagramPacket(byte[] buf, int length, InetAddress address, int port) :构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
Ø getAddress() :获取发送或接收方计算机的IP地址,此数据报将要发往该机器或者是从该机器接收到的。
Ø getData() :获取发送或接收的数据。
Ø setData(byte[] buf) :设置发送的数据。

UDP通信编程基本步骤:
1.创建客户端的DatagramSocket,创建时,定义客户端的监听端口。
2.创建服务器端的DatagramSocket,创建时,定义服务器端的监听端口。
3.在服务器端定义DatagramPacket对象,封装待发送的数据包。
4.客户端将数据报包发送出去。
5.服务器端接收数据报包。

【示例12-13】UDP:单向通信之客户端

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;public class Client {public static void main(String[] args) throws Exception {byte[] b = "北京尚学堂".getBytes();//必须告诉数据报包要发到哪台计算机的哪个端口,发送的数据以及数据的长度DatagramPacket dp = new DatagramPacket(b,b.length,new
InetSocketAddress("localhost",8999));//创建数据报套接字:指定发送信息的端口DatagramSocket ds = new DatagramSocket(9000);//发送数据报包ds.send(dp);//关闭资源ds.close();}
}

【示例12-14】UDP:单向通信之服务器端

import java.net.DatagramPacket;
import java.net.DatagramSocket;public class Server {public static void main(String[] args) throws Exception {//创建数据报套接字:指定接收信息的端口DatagramSocket ds = new DatagramSocket(8999);byte[] b = new byte[1024];//创建数据报包,指定要接收的数据的缓存位置和长度DatagramPacket dp = new DatagramPacket(b, b.length);//接收客户端发送的数据报ds.receive(dp); // 阻塞式方法//dp.getLength()返回实际收到的数据的字节数String string = new String(dp.getData(), 0, dp.getLength());System.out.println(string);//关闭资源ds.close();}
}

执行结果如图12-11所示:

通过字节数组流ByteArrayInputStream、ByteArrayOutputStream与数据流DataInputStream、DataOutputStream联合使用可以传递基本数据类型。

【示例12-15】UDP:基本数据类型的传递之客户端

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;public class Client {public static void main(String[] args) throws Exception {long n = 2000L;ByteArrayOutputStream bos = new ByteArrayOutputStream();DataOutputStream dos = new DataOutputStream(bos);dos.writeLong(n);//获取字节数组流中的字节数组(我们要发送的数据)byte[] b = bos.toByteArray();//必须告诉数据报包要发到哪台计算机的哪个端口,发送的数据以及数据的长度DatagramPacket dp = new DatagramPacket(b,b.length,new   InetSocketAddress("localhost",8999));//创建数据报套接字:指定发送信息的端口DatagramSocket ds = new DatagramSocket(9000);//发送数据报包ds.send(dp);//关闭资源dos.close();bos.close();ds.close();}
}

【示例12-16】UDP:基本数据类型的传递之服务器端

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;public class Server {public static void main(String[] args) throws Exception {//创建数据报套接字:指定接收信息的端口DatagramSocket ds = new DatagramSocket(8999);byte[] b = new byte[1024];//创建数据报包,指定要接收的数据的缓存位置和长度DatagramPacket dp = new DatagramPacket(b, b.length);//接收客户端发送的数据报ds.receive(dp); // 阻塞式方法//dp.getData():获取客户端发送的数据,返回值是一个字节数组ByteArrayInputStream bis = new ByteArrayInputStream(dp.getData());DataInputStream dis = new DataInputStream(bis);System.out.println(dis.readLong());//关闭资源dis.close();bis.close();ds.close();}
}

执行结果如图12-12所示:

通过字节数组流ByteArrayInputStream、ByteArrayOutputStream与数据流ObjectInputStream、ObjectOutputStream联合使用可以传递对象。

【示例12-17】UDP:对象的传递之Person类

import java.io.Serializable;
public class Person implements Serializable{private static final long serialVersionUID = 1L;int age;String name;public Person(int age, String name) {super();this.age = age;this.name = name;}@Overridepublic String toString() {return "Person [age=" + age + ", name=" + name + "]";}
}

【示例12-18】UDP:对象的传递之客户端

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;public class Client {public static void main(String[] args) throws Exception {//创建要发送的对象Person person = new Person(18, "高淇");ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);oos.writeObject(person);//获取字节数组流中的字节数组(我们要发送的数据)byte[] b = bos.toByteArray();//必须告诉数据报包要发到哪台计算机的哪个端口,发送的数据以及数据的长度DatagramPacket dp = new DatagramPacket(b,b.length,new InetSocketAddress("localhost",8999));//创建数据报套接字:指定发送信息的端口DatagramSocket ds = new DatagramSocket(9000);//发送数据报包ds.send(dp);//关闭资源oos.close();bos.close();ds.close();}
}

【示例12-19】UDP:对象的传递之服务器端

import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;public class Server {public static void main(String[] args) throws Exception {//创建数据报套接字:指定接收信息的端口DatagramSocket ds = new DatagramSocket(8999);byte[] b = new byte[1024];//创建数据报包,指定要接收的数据的缓存位置和长度DatagramPacket dp = new DatagramPacket(b, b.length);//接收客户端发送的数据报ds.receive(dp); // 阻塞式方法//dp.getData():获取客户端发送的数据,返回值是一个字节数组ByteArrayInputStream bis = new ByteArrayInputStream(dp.getData());ObjectInputStream ois = new ObjectInputStream(bis);System.out.println(ois.readObject());//关闭资源ois.close();bis.close();ds.close();}
}

执行结果如图12-13所示:

总结

1.端口是虚拟的概念,并不是说在主机上真的有若干个端口。
2.在www上,每一信息资源都有统一且唯一的地址,该地址就叫URL(Uniform Resource Locator),它是www的统一资源定位符。
3.TCP与UDP的区别
1)TCP是面向连接的,传输数据安全,稳定,效率相对较低。
2)UDP是面向无连接的,传输数据不安全,效率较高。
4.Socket通信是一种基于TCP协议,建立稳定连接的点对点的通信。
5.网络编程是由java.net包来提供网络功能。
1)InetAddress:封装计算机的IP地址和DNS(没有端口信息!)。
2)InetSocketAddress:包含IP和端口,常用于Socket通信。
3)URL:以使用它的各种方法来对URL对象进行分割、合并等处理。
6.基于TCP协议的Socket编程和通信
1)“请求-响应”模式:
–Socket类:发送TCP消息。
–ServerSocket类:创建服务器。
7.UDP通讯的实现
1)DatagramSocket:用于发送或接收数据报包。
2)常用方法:send()、receive()、 close()。
8.DatagramPacket:数据容器(封包)的作用
1)常用方法:构造方法、getAddrress(获取发送或接收方计算机的IP地址)、getData(获取发送或接收的数据)、setData(设置发送的数据)。

如何定位(IP\端口、URL)
TCP\UDP
Socket编程

Java基础6网络编程相关推荐

  1. JAVA基础11 网络编程

    JAVA基础 11.网络编程 1.什么是网络?网络模型?网络四要素? 1.网络 在计算机领域中网络是信息传输,接收,共享的虚拟平台,通过它把各个点,面,体的联系到一起,从而实现这些资源的共享. 资源的 ...

  2. Java基础:网络编程

    1. 网络编程概述 自从互联网诞生以来,现在基本上所有的程序都是网络程序,很少有单机版的程序了. 计算机网络就是把各个计算机连接到一起,让网络中的计算机可以互相通信.网络编程就是如何在程序中实现两台计 ...

  3. java基础:网络编程(一)简介

    网络编程简介 这些知识点在学习计算机网络时都有详细讲,我这就简单介绍下,具体的看计算机网络相关知识. 1.软件结构 常见的软件结构有C/S和B/S C/S (Client/Server) 表示客户端/ ...

  4. java基础篇---网络编程(IP与URL)

    一:IP与InetAddress 在Java中支持网络通讯程序的开发,主要提供了两种通讯协议:TCP协议,UDP协议 可靠地连接传输,使用三方握手的方式完成通讯 不可靠的连接传输,传输的时候接受方不一 ...

  5. Java基础之网络编程

    网络编程 1.1 网络编程的基本概念 1.网络 将不同区域的电脑连接到一起,组成局域网.城域网或广域网.把分布在不同地理区域的计算机与专门的外部设备用通信线路互联成一个规模大.功能强的网络系统,从而使 ...

  6. Java基础23 网络编程 socket套接字流 TCP传输总结

    一.网络编程的概念 1.计算机网络:将不同地区的计算机,使用网络来进行连接 实现不同地区的数据的交互与共享(互联时代) 2. 网络编程的三要素:IP地址 端口号 协议 3. ip地址:是在网络连接中 ...

  7. 大数据 -- java基础16 网络编程 TCP UDP

    1.网络编程的三要素:(1)IP地址(2)端口号(3)协议 2.IP地址 : 网络中计算机唯一标识. (1)IP地址在计算机中存储的时候是由二进制的形式进行存储的:IP:192.168.7.42 十进 ...

  8. Java基础进阶网络编程概述

    一.网络编程中有两个主要的问题: 1.如何准确地定位网络上一台或多台主机:定位主机上的特定的应用 2.找到主机后如何可靠高效地进行数据传输 二.网络编程中的两个要素: 1.对应问题一:IP和端口号 2 ...

  9. Java 基础之网络编程

    网络编程 主要内容 软件架构CS/BS 网络通信三要素 TCP通信 Socket套接字 ServerSocket 第一章 网络编程入门 1.1软件结构 C/S结构 :全称为Client/Server结 ...

最新文章

  1. 数组、链表、Hash(转)
  2. java的死锁是什么意思_Java面试题:什么是死锁?如何手写一个死锁(Dead Lock)...
  3. timeval的时间转换成毫秒之后多大的数据类型可以装下
  4. VS2015 中使用 MVC4
  5. 平面设计素材|现代色彩风格的海报设计
  6. 全球 42 亿 IPv4 地址宣告耗尽!
  7. Q90:简易地模拟透明材质(Simple Transparency)
  8. 视频压缩编码基础知识(上)
  9. python测试用例设计方法_设计测试用例的基本方法
  10. Servlet 原理概述
  11. Vivado官网下载
  12. PDMS二次开发(二十)——关于1.0.2.0版本升级内容的说明
  13. 家用汽车维修3:基于OBDII的故障分析
  14. 少儿编程scratch与机器人
  15. 重庆市渝中区相关部门负责人到访 Conflux 探讨新一线城市区块链技术发展路径...
  16. 如何在共享中添加计算机,如何在网上邻居中添加共享文件夹
  17. Linux系统学习了解计算机
  18. Locating Elements(二)
  19. 轻松矿工没有内核_使用内核迁移器可以轻松进行SharePoint迁移
  20. 剑指Offer(较难)

热门文章

  1. 超级搞笑~`记得转噢
  2. 让iPhone输入法更有“苹果”味 (一)
  3. python请编写程序、生成随机密码_python生成随机密码串
  4. u盘中文件不能显示解决方法
  5. oracle随机生成记录_区块链上的随机性:概述与构造
  6. 上海法登阀门受邀出席2023年3月30号济南生物发酵展
  7. 2012盘点“孔子”周润发的经典语录年度经典语录励志天
  8. STM32F103GPIO-LED点灯
  9. 阿里码农改简历为区块链工程师相亲 猛收360份求爱信
  10. qq游戏大厅 android,QQ游戏中心(android)(原创教程)