黑马程序员——Java网络编程(TCP和UDP)

时间:2021-07-21 11:38:49
黑马程序员——Java网络编程(TCP和UDP)
---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、<a 
href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! -------------------------------

概念:什么是TCP和UDP


TCP是一种面向连接的、可靠的、基于字节流的运输层通信协议。也就是说只有建立了可靠的连
接才能进行通信,因为他们是结果三次“握手”的过程,是指先发送一次数据包,问候一下,"在吗"然后等待对方确认收
到并回复一次包,最后在开始发送数据包。
比如:打电话需要先建立连接,三大运营商需建立通讯基站,通讯网络信号覆盖,通讯连接后才能通电话。A打电话B,拨通B号码,等待B接电话,B没接到(关机)就无法通讯,如果接到就
能通讯,QQ视频聊天、等都是TCP。
TCP特点:传输安全性高,适应于用于一次传输大量报文的情形,如涉及到机密重要的文件传输,远程登录等。


UDP :是指用户数据报协议,面向非连接的传输。只管发生数据出去,不管对方是否收到。
举例:发短信问候,不管对方啥时候查看,我只管发短信出去,广场喇叭广播、火车的语言播报。
UDP特点:安全度不高,传输效率快,不用建立连接,服务效率高,适用于不考虑安全度少量的数据传输。


一、UDP的发送端
package com.itheima.net;


import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;


public class UdpSendDemo {


/**
* @param args

* 创建UDP发送端
* 分析:1.建立Udp的 socket服务。
*     2.将要发送的数据封装到包中、(打包数据)
*     3.通过udp的socket 服务发送 
* @throws IOException 


*/
public static void main(String[] args) throws IOException {

System.out.print("007呼叫发送端启动。。。。。。。。。。。");

// 1.socket 服务使用 DatagramSocket对象

DatagramSocket ds=new DatagramSocket(10086);

String str="呼叫总部,哥们来吧!";
byte[] bt=str.getBytes();

//数据封装到对象包中
DatagramPacket  dp=new DatagramPacket(bt, bt.length,InetAddress.getByName("192.168.1.110"),10000);

// ds对象的send方法发送出去
  ds.send(dp);
  
  ds.close();


}


}


二.UDP接收端:
package com.itheima.net;


import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;


public class UdpReceDemo {


/**
* @param args
* 创建UDP接收
* 分析:1.建立Udp的 socket服务。明确一个端口
*     2.将创建数据包 接收存储收到的数据信息,方便解析
*     3.socket 的接收Reseive 方法接收存储数据
*     4.通过数据包解析数据
* @throws IOException 
*/
public static void main(String[] args) throws IOException {

// 1.socket 服务使用 DatagramSocket对象

DatagramSocket ds=new DatagramSocket(10086);

// 2.创建包数据封装到对象包中
String str="总部 服务接收启动!";
byte[] bt=str.getBytes();

DatagramPacket  dp=new DatagramPacket(bt, bt.length); 
//3.接收数据
 ds.receive(dp);
 
//4.通过数据包解析数据
String ip=dp.getAddress().getHostAddress();//获取host地址
int port=dp.getPort();  //获取端口
 
String text=new String(dp.getData(),0,dp.getLength());

        System.out.print(ip+":"+port+":"+text);
        
        ds.close();
}


}


聊天程序(多线程)


package com.itheima.net;


import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;


public class ChatDemo {


/**
* @param args
* @throws IOException 
*/
public static void main(String[] args) throws IOException {
//1.发送端服务对象
DatagramSocket send=new DatagramSocket();
//Send s=new Send();

//2.接收多服务对象
DatagramSocket Res=new DatagramSocket(10001);
//Rese r=new Rese();
Thread t1=new Thread(new Send(send));
t1.start();
Thread t2 =new Thread(new Rese(Res));
t2.start();
}


}


class Send implements Runnable{
     private DatagramSocket ds;
  
public Send(DatagramSocket send) {
// TODO Auto-generated constructor stub
}
public  void Send(DatagramSocket ds){
    this.ds=ds;
     
     }
@Override
public void run() {

try {
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));

String line=null;
while((line=bufr.readLine())!=null){
byte[] bt=line.getBytes();
//数据封装到对象包中
DatagramPacket  dp=new DatagramPacket(bt, bt.length,InetAddress.getByName("192.168.1.255"),10001);

if("888".equals(line)){
break;
}
ds.close();
}
} catch (Exception e) {
// TODO: handle exception
}

}

}
class Rese implements Runnable{
       //1.创建服务对象
  private DatagramSocket ds;
  
    public Rese(DatagramSocket res) {
// TODO Auto-generated constructor stub
}
public  void Rese(DatagramSocket ds){
    this.ds=ds;
     
    }
@Override
public void run() {
try {
while(true){
//2. 接收数据包
byte [] bt=new byte[1024*4];

DatagramPacket  dp=new DatagramPacket(bt, bt.length); 
//3.接收数据
 ds.receive(dp);
 
//4.通过数据包解析数据
String ip=dp.getAddress().getHostAddress();//获取host地址
int port=dp.getPort();  //获取端口
 
String text=new String(dp.getData(),0,dp.getLength());

       System.out.print(ip+":"+port+":"+text);
       if("888".equals(text)){
          System.out.print("退出聊天室,天晚了回家睡觉、、、、");
       }
       ds.close();
}
} catch (Exception e) {
// TODO: handle exception
}

}

}


三.TCP 建立客户端


package com.itheima.net;


import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;


public class TcpClientDemo {


/**
* @param args
*  客户端发送到服务器端,TCP传输过程
* 分析思路:1.创建TCP客户端socket 服务对象,使用该对象创建一个明确的目的地,链接主机。
*       2.如果链接成功,说明传输通道已经建立,通道就是socket流,是底层建立好的,有输入输出,
*       可以通过socket获取输入输出对象  ,getOutputStream(),,getInputStream()来获取字节流
*       3.使用输入输出流,读写数据
*       4.关闭资源
* @throws IOException 
* @throws UnknownHostException 
*/
public static void main(String[] args) throws UnknownHostException, IOException {

//1.创建客户端服务对象
Socket st=new Socket("192.168.1.100",10002);
//2.获取输出流
OutputStream out=st.getOutputStream();

//3.输出的数据写出去
            String str="TCP上传,哥们我又来了欢迎不?";  
            out.write(str.getBytes());
         //4.关闭   
            st.close();
}


}
报错:
Exception in thread "main" java.net.ConnectException: Connection timed out: connect
at java.net.DualStackPlainSocketImpl.connect0(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:69)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:157)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:391)
at java.net.Socket.connect(Socket.java:579)
at java.net.Socket.connect(Socket.java:528)
at java.net.Socket.<init>(Socket.java:425)
at java.net.Socket.<init>(Socket.java:208)
at com.itheima.net.TcpClientDemo.main(TcpClientDemo.java:24)


四:TCP建立服务端
package com.itheima.net;


import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;


public class TcpServerDemo {


/**
* @throws IOException 
* @Author hutian
* 服务端接收客户端发送的数据,打印出来
* TCP服务器端思路:
* 分析:1.同样要创建socket 服务,建立ServerSocket服务端对象
*     2.服务端必须对外提供端口,否则无法连接
*     3.获取连接过来的客户端对象
*     4.通过客户端对象读取,客户端发送过来的数据,并打印出来
*     5.关闭流
*/
public static void main(String[] args) throws IOException {
// 创建服务端对象
ServerSocket ss=new ServerSocket(10002);  //记得要提供端口
         //获取客户端
Socket sk=ss.accept(); //阻塞式

String ip=ss.getInetAddress().getHostAddress();

//通过Socket 对象getInputStream()获取输入流
InputStream in=sk.getInputStream();

byte[] bt=new byte[1024];
int len=0;

while((len=in.read(bt))!=-1){

String text=new String(bt,0,len);
   System.out.print(ip+":"+text);
}
ss.close();
sk.close();
}


}


TCP 建立交互方式
1.客户端
package com.itheima.net;


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;


public class ClientDemo2 {


/**
* @param args
*  客户端发送到服务器端,TCP传输过程
* 分析思路:1.创建TCP客户端socket 服务对象,使用该对象创建一个明确的目的地,链接主机。
*       2.如果链接成功,说明传输通道已经建立,通道就是socket流,是底层建立好的,有输入输出,
*       可以通过socket获取输入输出对象  ,getOutputStream(),,getInputStream()来获取字节流
*       3.使用输入输出流,读写数据
*       4.关闭资源
* @throws IOException 
* @throws UnknownHostException 
*/
public static void main(String[] args) throws UnknownHostException, IOException {

//1.创建客户端服务对象
Socket st=new Socket("192.168.1.100",10002);
//2.获取输出流
OutputStream out=st.getOutputStream();

//3.输出的数据写出去
           String str="TCP上传,哥们我又来了欢迎不?";  
           out.write(str.getBytes());
           
         //读取服务端返回的数据
           InputStream in=st.getInputStream();
           
           byte[] bt=new byte[1024*4];
           
           int len=in.read(bt);
           
           String text=new String(bt,0,len);
           System.out.print(text);
        //4.关闭   
           st.close();
}


}


2.服务端
package com.itheima.net;


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;


public class ServerDemo2 {


/**
* @throws IOException 
* @Author hutian
* 服务端接收客户端发送的数据,打印出来
* TCP服务器端思路:
* 分析:1.同样要创建socket 服务,建立ServerSocket服务端对象
*     2.服务端必须对外提供端口,否则无法连接
*     3.获取连接过来的客户端对象
*     4.通过客户端对象读取,客户端发送过来的数据,并打印出来
*     5.关闭流
*/
public static void main(String[] args) throws IOException {
// 创建服务端对象
ServerSocket ss=new ServerSocket(10004);  //记得要提供端口
        //获取客户端
Socket sk=ss.accept(); //阻塞式

String ip=ss.getInetAddress().getHostAddress();

//通过Socket 对象getInputStream()获取输入流
InputStream in=sk.getInputStream();

byte[] bt=new byte[1024];
int len=in.read(bt);



String text=new String(bt,0,len);
   System.out.print(ip+":"+text);
 
   // 使用客户端对象输出流 给客户端发送数据
  OutputStream out=sk.getOutputStream();
  out.write("总部收到over".getBytes());

ss.close();
sk.close();


}


}
小结一下:1.无论客户端还是服务端,显得创建Socket 服务对象 客户端要指定端口访问
          2.客户端发送,输出流,把数据写出去告诉人家
          3.服务端对象先获取客户端对象,用他获取输进来的流数据,使用客户端输出流返回客户端一个信息 
          操作的是客户端。
          
问题:老是提示ip地址占用
Exception in thread "main" java.net.BindException: Address already in use: JVM_Bind
at java.net.DualStackPlainSocketImpl.bind0(Native Method)
at java.net.DualStackPlainSocketImpl.socketBind(DualStackPlainSocketImpl.java:96)
at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:376)
at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:175)
at java.net.ServerSocket.bind(ServerSocket.java:376)
at java.net.ServerSocket.<init>(ServerSocket.java:237)
at java.net.ServerSocket.<init>(ServerSocket.java:128)
at com.itheima.net.ServerDemo2.main(ServerDemo2.java:24)

练习:上传服务端与客户端
1.客户端:
package com.itheima.net;


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;


public class UploadServer {


/**
* @param args
* @throws IOException 
*/
public static void main(String[] args) throws IOException {


         System.out.print("来吧,等你上传服务端。。。。。");
         
         ServerSocket ss=new ServerSocket(10008);
         
         //2.获取到客户端对象
         
         Socket sk=ss.accept();
         System.out.print(sk.getInetAddress().getHostAddress()+"......成功连接");
         
         BufferedReader bufr=new BufferedReader(new InputStreamReader(sk.getInputStream()));
         
         BufferedWriter bufw=new BufferedWriter(new FileWriter("D:\\log.txt"));
         
         String line=null;
         
         while((line=bufr.readLine())!=null){
         
        bufw.write(line);
        bufw.newLine();
        // bufw.close();
        bufw.flush();
         }
         
         //
         PrintWriter out=new PrintWriter(sk.getOutputStream(),true);
                    out.print("恭喜您,上传成功啦!");
                    
                    bufw.close();
                    
                   ss.close();
                   sk.close();
}


}
打印:
请注意,我要上传文件啦。。。。。
true
Exception in thread "main" java.net.ConnectException: Connection timed out: connect
at java.net.DualStackPlainSocketImpl.connect0(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:69)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:157)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:391)
at java.net.Socket.connect(Socket.java:579)
at java.net.Socket.connect(Socket.java:528)

2.服务端
package com.itheima.net;


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;


public class UploadServer {


/**
* @param args
* @throws IOException 
*/
public static void main(String[] args) throws IOException {


         System.out.println("亲来吧,等你上传服务端。。。。。");
         
         ServerSocket ss=new ServerSocket(10008);
         
         //2.获取到客户端对象
         
         Socket sk=ss.accept();
         System.out.print(sk.getInetAddress().getHostAddress()+"......成功连接");
         
         BufferedReader bufr=new BufferedReader(new InputStreamReader(sk.getInputStream()));
         
         BufferedWriter bufw=new BufferedWriter(new FileWriter("D:\\server.txt"));
         
         String line=null;
         
         while((line=bufr.readLine())!=null){
         
        bufw.write(line);
        bufw.newLine();
        // bufw.close();
        bufw.flush();
         }
         
         //
         PrintWriter out=new PrintWriter(sk.getOutputStream(),true);
                    out.print("恭喜您,上传成功啦!");
                    
                    bufw.close();
                    
                   ss.close();
                   sk.close();
}


}

打印:
来吧,等你上传服务端。。。。。
Exception in thread "main" java.net.BindException: Address already in use: JVM_Bind
at java.net.DualStackPlainSocketImpl.bind0(Native Method)
at java.net.DualStackPlainSocketImpl.socketBind(DualStackPlainSocketImpl.java:96)
at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:376)
at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:175)
at java.net.ServerSocket.bind(ServerSocket.java:376)
at java.net.ServerSocket.<init>(ServerSocket.java:237)
at java.net.ServerSocket.<init>(ServerSocket.java:128)
at com.itheima.net.UploadServer.main(UploadServer.java:22)


TCP和UDP总结:
TCP:    1.建立连接,形成传输数据的通道。
         2.在连接中进行大数据传输。
         3.通过三次握手完成连接,是可靠协议。
         4.因为必须建立连接,所以效率会稍低。
主要用于数据下载,文件传输,可靠性要求高的应用
UDP:     1.将数据及源和目的封装成数据包中,不需要建立连接。
          2.每个数据报包的大小在限制在64k内。
          3.因无连接,是不可靠的协议。
          4.不需要建立连接,速度快。
应用:传输视频,mp3等


---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、<a 
href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! -------------------------------