黑马程序员——JAVA基础---网路编程---概述,UDP/TCP对应Socket,小知识点

时间:2023-02-17 08:10:45

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

第一讲. 概述

网络通信要素:IP(本地回环地址 127.0.0.1 ,主机名localhost), 端口(0~65535),  协议

网络层次:OSI参考模型,7层参考模型;TCP/IP的参考模型:应用层(如 http),传输层(如 TCP),网际层(如 IP),主机至网络层

两大传输协议:

UDP(好比:步话机) TCP(好比:打电话)
  1. 将数据及源和目的封装成数据包,不需要建立连接
  2. 数据包的大小限制在64k内
  3. 因无连接,是不可靠传输
  4. 速度快
  5. 适用:聊天,视频会议,桌面共享
  1. 建立连接,形成数据传输的通道
  2. 在连接中进行大数据量传输
  3. 通过三次握手完成连接,是可靠协议
  4. 必须建立连接,效率稍低

  1. Java中的ip对象  InetAddress,单例设计模式,通过getLocalHosh(),getByAddress(),getByName()等方法获得实例对象
  2. socket 套接字 ,Java靠Socket完成网络的传输层通信,即收发数据包。

第二讲. DatagramSocket   :UDP的Socket

  1.  *.*.*.255是广播地址,*.*.*.0代表一个网络段
  2. 由于端口可能还未释放,反复运行发送程序系统会自动顺延端口号,当然也可以指定发送端口
  3. 定义udp接受端时,需要监听某一个端口,其实就是给这个接收网络应用程序定义一个数字标识
  4. 重复new Socket会发生BindExcepiton 重复绑定异常
    import java.net.*;
    import java.io.*;
    class UDPSend
    {
    public static void main(String[] args) throws Exception
    {
    DatagramSocket ds = new DatagramSocket();
    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    while(true){
    String line = in.readLine();//阻塞式方法
    if("886".equals(line))
    break;
    byte[] data = line.getBytes();
    //构造方法为:DatagramPacket(byte[] buf, int length, InetAddress address, int port)
    DatagramPacket dp = new DatagramPacket
    (data,data.length,InetAddress.getByName("59.66.201.255"),50000);//广播地址
    ds.send(dp);
    }
    in.close();
    ds.close();//端口可能还未释放,反复运行发送程序系统会自动顺延端口号
    }
    }

    class UDPReceive
    {
    public static void main(String[] args) throws Exception
    {
    DatagramSocket ds = new DatagramSocket(50000);
    while(true){
    //DatagramSocket ds = new DatagramSocket(50000); // BindException重复绑定异常
    byte[] buff = new byte[1024];
    DatagramPacket dp = new DatagramPacket(buff,buff.length);
    ds.receive(dp);//阻塞式的方法

    String ip = dp.getAddress().getHostAddress();
    String data =new String(dp.getData(),0,dp.getLength());
    System.out.println("ip::"+ip+"\tdata::"+data);
    System.out.println(dp.getPort());
    }
    //ds.close();
    }
    }

第三讲. Scoket,ServerSocket :TCP的套接字对象

  1. Socket:在建立时就可以连接主机,因为TCP是面向连接的
  2. ServerSocket:服务端,建立是要绑定端口,通过accept阻塞式方法接收客户端socket对象
  3. 现象:客户端和服务端都在莫名的等待。 原因:两端的阻塞式方法未读到结束标志。
    /*从客服端的键盘录入文本数据。服务器接收到数据,转化为大写并转发回客户端。客户端将其打印到控制台上*/
    import java.io.*;
    import java.net.*;
    class TcpClient
    {
    public static void main(String[] args) throws Exception
    {
    BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
    String line;
    while(!((line=input.readLine()).equals("over")))
    {
    Socket socket = new Socket("127.0.0.1",50000);
    PrintWriter out = new PrintWriter(socket.getOutputStream(),true);//这里必须autoflush
    out.println(line);
    BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    String data = in.readLine();
    System.out.println("从服务端转发来的大写数据:"+data);
    socket.close();
    }
    }
    }
    class TcpServer
    {
    public static void main(String[] args) throws Exception
    {
    ServerSocket ss = new ServerSocket(50000);
    while(true){
    Socket s = ss.accept();
    String ip = s.getInetAddress().getHostAddress();
    System.out.println("ip::"+ip);
    BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
    String data = (in.readLine()).toUpperCase();
    PrintWriter out = new PrintWriter(s.getOutputStream(),true);
    out.println(data);
    s.close(); //在服务器端必须关闭Socket以断开客服端连接
    }
    }
    }

练习:复制文本文件,Socket中shutdownOutputStream()方法的应用:写入结束符。

import java.io.*;
import java.net.*;

class TextClient
{
public static void main(String[] args) throws Exception
{
BufferedReader in = new BufferedReader(new FileReader("TCPDemo.java"));
Socket s = new Socket("127.0.0.1",50000);
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
String line;
while((line=in.readLine())!=null){
out.println(line);
}
s.shutdownOutput();//out.println("over");
s.close();
}
}
class TextServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(50000);
while(true)
{
Socket s = ss.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter out = new PrintWriter("TCPDemo.txt");
String line;
while((line=in.readLine())!=null){
out.println(line);
}
out.close();
s.close();
System.out.println("文件复制成功!");
}
}
}

练习:服务端多线程,实现并发登陆

/***客户端通过键盘录入用户名,服务端进行校验
如果用户存在,服务端显示XXX,已登陆;客户端显示XXX,欢迎光临
如果不存在,服务端显示XXX,尝试登陆;客户端显示XXX,用户不存在,最多校验三次
**/
import java.net.*;
import java.io.*;
class ClientThread implements Runnable
{
private Socket s;
ClientThread(Socket s){this.s = s;}
private boolean checkName(String name) throws IOException
{
BufferedReader in = new BufferedReader(new FileReader("Logname.txt"));
String line;
while((line = in.readLine())!=null)
if(line.equals(name)) return true;
return false;
}
public void run(){
int count = 3;//设置重复校验次数
try
{
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
while((count--)!=0){
String name = in.readLine();
if(checkName(name)){
System.out.println(name+",已登陆");
out.println(name+",欢迎光临");
return;
}
else{
System.out.println(name+",尝试登陆");
out.println(name+",该用户不存在");
}
}
s.shutdownOutput();
s.close();
}
catch (Exception e)
{
throw new RuntimeException("登陆异常!");
}
}
}
class LoginClient//客户端
{
public static void main(String[] args) throws Exception
{
Socket s = new Socket("127.0.0.1",20000);
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
String line,name;
while(true){
System.out.println("请输入登陆名:");
name = input.readLine();
out.println(name);
line = in.readLine();
if(line==null) break;
else if(line.equals(name+",欢迎光临"))
{
System.out.println(line);
break;
}
else System.out.println(line);
}
input.close();
s.close();
}
}
class LoginServer//服务端
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(20000);
while(true){
Socket s = ss.accept();
new Thread(new ClientThread(s)).start();//为新加入的客户创建线程
}
}
}

第四讲. 小知识点
  1. InetAddress类是对IP地址的封装。
  2. Socke的connect(SocketAddress endpoint)方法中,SocketAddress 叫做套接字地址,是抽象对象。其子类InetSocketAddress,实现了(IP地址+端口号)的封装。
  3. ServerSocket的构造方法 ServerSocket(int port, int backlog)中的int backlog指的是指定服务端最大连接数,限定了同时在线的客户数。
  4. URL 代表一个统一资源定位符,它是指向互联网“资源”的指针(就是封装了域名)。URI类代表一个统一资源标识符 (URI) 引用(比URL范畴广一点)。URL的openConnecton()方法返回一个URLConnection 对象,它表示到URL 所引用的远程对象的连接(在应用层上的网络连接,里面封装了Socket,好处是去掉了http等应用层协议的消息头,只保留消息主体)。
  5. 域名解析:就是把域名(主机名)演绎成IP地址,即DNS(DomainNNameSystem)。先找本地的hosts文件中查找,再在配置中指定的DNS服务器去解析域名。