**Java套接字编程-由浅入深**

套接字编程TCP/UDP:
在java里面有专门的类负责客户端和服务端通信的任务,而通信的种类有两种:TCP和UDP,TCP是典型的服务端/客户端模型,他通过客户端和服务端的连接,使用java IO流来达到效果。而在UDP中,我们用到的是数据报来进行通信。tcp通信需要建立专门的连接通道,通过这个通道进行通信,udp则是以数据报的接收发送达到通信效果。二者的区别在于是否需要建立通信通道。举个简单的例子:TCP通信就相当于是打电话,你给别人打电话,你需要知道别人的电话号码,就相当于IP地址。电话打通后,拨打电话的双方之间就是有信号通道,互相之间能听到对方说的话,一旦电话挂断,通信通道销毁,这个时候你就什么也听不到了。这个时候你就会想能不能发短信呢,当然能,UDP就相当于发送短信,我只需要知道对方的电话号码,直接编辑短信发给他就是了,不再需要建立专门的通道哦,但是UDP有一个明显的缺点就是消息不及时,手机收到短信几天甚至十几天过后才看到是常有的事,所以UDP的缺点就在于不能及时让对方知道,甚至对方可能接收不了。但是两种通信方式在实际编程中互相结合使用,互相弥补优缺点。

TCP:
tcp中涉及到的主要有两个类:SocketServerSocket,Socket用于客户端,ServerSocket用于服务端。
Socket的用法:Socket socket = new Socket(ip,port);最常用的构造方法之一,含义是连接到地址为ip的服务器上,端口为port.一般socket通信使用IO流来进行写入和读取,客户端向流里面写东西,socket通过调用getInputStream()getOutputStream()方法来获取输出输入流,服务端从流里面把数据读取出来过后又向流里面写入东西,客户端再从流里面读取信息,完成一次对话:

    BufferedWriter bw = new BufferedWriter(new InputStreamWriter(socket.getOutpouStream()));
     bw.write("hello world");

 //一定要加这句话,将缓冲区的内容全部排出
bw.fllush();
`ServerSocket`用法:`ServerSocket serversocket = new ServerSocket(port)`;建立监听窗口,等待连接:
//发方法在没有接收到客户端的连接请求时一直处于阻塞状态,返回值是Socket
  

Socket socket = serversocket.accept();
      //建立输入流,读取客户端发来的信息
      `BufferedReader br = new BufferedReader(new`  

InputStreamReader(socket.getInputStream()));
 byte[] buf = new byte[2048];
     //调用read方法,将流里面的内容读取到byte数组中,并返回其长度
  

       int len = in.read(buf);
     //将byte数组转换为字符串
     System.out.println(new String(buf,0,len) );
    再向客户端写东西:
        BufferedReader bo= new BufferedWriter(new   InputStreamWriter(socket.getOutputStream()));
        String s = "客户你好,我已收到消息";
        bo.write(s);
在客户端里再用BufferedReader将信息读取出来即可.

下面用具体例子给大家讲解:
客户端:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class Client {
private int port;

private String address;

private Socket socket;

private BufferedWriter out;

private BufferedReader in;
public Client(int port,String address){
	
	this.port = port;
	
	this.address = address;
	
}

public void start() throws UnknownHostException, IOException{
	
	//发送连接请求
	socket = new Socket(address,port);
	
	//输入流
	in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    
	out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
	//向流里面输入内容
	
	out.write("快来和我聊天吧"); 

    out.flush();
	
    System.out.println("向服务端发送数据:");
    	 
    	try{
    		//while的作用是能一直从键盘读入
    		while(true){	
                //不要用readLine()该方法容易引起阻塞
    			char[] cbuf = new char[2048];
    			
    			int len = in.read(cbuf);
    			
    			System.out.println("收到服务端回话:"+new String(cbuf,0,len));
    			
    			Scanner scan = new Scanner(System.in);
    			
    			String s = scan.next();
    			if(!s.equals("再见")){
	        		
    	            out.write(s);
    	        	
    	        	out.flush();
    	        	
    	        	}else{
    	        			socket.close();
    	        			in.close();
    	        			out.close();
    	        			socket.close();
    	        	}
    		 }
    			}catch(Exception e){
    				
    				e.printStackTrace();
    			}finally{
    				
    				try{
    				System.out.println("所有连接已关闭");
    				}catch(Exception e){
    					e.printStackTrace();
    				}
    			}
}

   public static void main(String[] args) throws UnknownHostException, IOException{
	   Client client = new Client(9994,"127.0.0.1");
	   client.start();
}

}

服务端:

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;
import java.util.Scanner;

public class Service {

	private  BufferedReader in;
	
	private BufferedWriter out;
	
	private ServerSocket serversocket;
	
	private Socket socket;
	
	private int port;
	
	public Service(int port){
		
		this.port = port;
		
	}
	
	public void response() throws IOException, InterruptedException{
		
		 try {		
					//建立监听端口
			serversocket = new ServerSocket(this.port);
			
			System.out.println("准备接收客户端发来的数据:");
			//阻塞,等待客户端发请求
		    socket = serversocket.accept();
		    
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			
		    out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
		  
		    System.out.println("连接成功,客户端信息:"+socket);
		    //为客户端开一个新线程
		    try{
		    	while(true){
			    char[] cbuf = new char[2048];
			   
			    int len = in.read(cbuf);	

		        System.out.println("收到客户端消息:"+new String(cbuf,0,len));
		        //out.write("我已经给你连接上了,开始聊天吧");
		        //必须要用上out.flush,不然数据在缓冲区中,不能被读取
		        //out.flush();
		        Scanner scan = new Scanner(System.in);
		                  	        	 
		        String s = scan.next();
		        	
		        if(!s.equals("再见")){
		        		
		            out.write(s);
		        	
		        	out.flush();
		        	
		        	}else{
		        			serversocket.close();
		        			in.close();
		        			out.close();
		        			socket.close();
		        	}
		    	}
		        }catch(Exception e){
		        	e.printStackTrace();
		        }
			//向客户端发送内容
			//建议不要用nextLine,因为该方法读取的是行,如果没读取到换行符,则会一直读下去,造成阻塞
		} catch (IOException e) {
		
			e.printStackTrace();
		} 			
	}
	
	 
	 /*public class LogicThread extends Thread{
		
		 private  BufferedReader in;
		 private BufferedWriter out;
		 private ServerSocket serversocket;
		 private Socket socket;
		 public LogicThread(BufferedReader in,BufferedWriter out,Socket socket,ServerSocket serversocket){
			 this.in = in;
			 this.out = out;
			 this.socket = socket;
			 this.serversocket = serversocket;
		 }
		 public void run(){
			 
		 while(true){
			 
			
		 }
	 }
 }*/
	public static void main(String[] args) throws IOException, InterruptedException{
		
		Service service = new Service(9994);
		
		service.response();
		
		//service.serversocket.close();
	}
}

UDP编程:

客户端:

DatagramSocket:套接字,相当于电话,使用方法:
DatagramSocket  ds = new DatagramSocket();可以不需要绑定任何地址,因为你发送短信给别人的时候,任何手机都可以用,你只需要在发送短信的时候记住电话号码就行了
DatagramPacket:数据报,相当于短信,使用方法:
String s = "heelo world";
byte[] buf = s.getBytes();
DatagramPacket dp = new DatagramPacket(buf,buf.length,Ip,port);
上面的IP就相当于电话号码,长度就是短信大小。
然后用电话把短信发出去:ds.send(dp);

服务端:
服务端需要建立监听端口,如果你手机关机别人是接收不到的,所以开机监听:
DatagramSocket ds = new DatagramSocket(port);
接收:
byte[] buf = new btye[2048]
//构造数据报
DatagramPacket dp = new DatagramPacket(buf,buf.length);
将收到的内容放到dp中
ds.receive(dp);
读取:
byte[] buf1 = dp.getData();
System.out.println(new String(buf1,0,buf1.length()));
返回结果给客户端:
String s = "收到";
byte[] buf2 = s.getBytes();
//通过接收到的数据报获得客户端的ip和port,并向他返回信息
ds.send(buf2,buf2.length,dp.getAddress(),dp.getPort());

客户端再通过receive()方法收到服务端返回的消息即可完成一次通信。

实例:
客户端:

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Scanner;

public class Client {
 
	private int port;
	
	private InetAddress address;
	//发送报文给服务端
	private DatagramPacket send;
	//接收服务端发送过来的报文
	private DatagramPacket recieve;
	
	private DatagramSocket socket;
	
	public Client(int port,InetAddress address){
		
		this.port = port;
		this.address = address;
	}
	public void send()  {
		//不需要绑定具体的发送地点,类似于邮局,你不需要在固定的邮局寄东西,所以这不绑定ip都可以,信封上有就行了
		try{
			
		socket = new DatagramSocket();
		//发送
		Scanner  scan = new Scanner(System.in);
		
		while(true){
        
		String s = scan.next(); 	 
        //将字符串转换到byte类型的buf数组里面
		byte[] buf = s.getBytes();
		
		send = new DatagramPacket(buf,buf.length,address,port);
		
		socket.send(send);
		
		System.out.println("发送成功,等待服务端响应");
		//接收
		
		byte[] rbuf = new byte[2048];
		
		recieve = new DatagramPacket(rbuf,rbuf.length);
		
		//未收到服务端消息时阻塞
		socket.receive(recieve);
		//用于接收
		byte[] rbuf1 = recieve.getData();
		
		int len = rbuf1.length;

		System.out.println("服务端说:"+new String(rbuf1,0,len));
		}
		}catch(Exception e){
			
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) throws UnknownHostException{
		
		Client client = new Client(9998,InetAddress.getByName("127.0.0.1"));
		
		client.send();
		
	}
}

服务端:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.Scanner;

public class Service { 
	 
	 private int port;
	 private DatagramPacket send;
	 private DatagramPacket recieve;
	 private DatagramSocket socket;
	 
	 public Service(int port){
		 
		 this.port = port;
	 }
	 
	 public void recieve() throws IOException{
		 //建立监听窗口
		 socket = new DatagramSocket(port);
		 
		 System.out.println("服务器已经启动");	 
			 //开启新线程为客户端处理事务
		 new LogicThread(recieve,socket);
			 //System.out.println("发送成功");
	 }
	 
	 public class LogicThread extends Thread{
	  
		 public DatagramPacket recieve;
		 public DatagramSocket socket;
		 
		 public LogicThread(DatagramPacket recieve,DatagramSocket socket){
			 this.recieve = recieve;
			 this.socket = socket;
			 start();
		 }
		 public void run(){
			
			 try{
				 
			//while的作用是一直接接收数据包
             while(true){
			
             byte[] rbuf = new byte[2048];
    			 //封装数据报,用于接收数据
    		 recieve = new DatagramPacket(rbuf,rbuf.length);
    			 //等待客户端发来数据,不然阻塞
    		 socket.receive(recieve);	 
            	 
             byte[] buf = recieve.getData();
			 
			 int len = buf.length;
			 
			 System.out.println("客户端发来数据:"+new String(buf,0,len));
			 
			 //向客户端发送数据
			 Scanner scan = new Scanner(System.in);
			 
			 String s = scan.next();
			   
			 byte[] sbuf = s.getBytes();
			 
			 send = new DatagramPacket(sbuf,sbuf.length,recieve.getAddress(),recieve.getPort());
			 
			 socket.send(send);
			 }
			 }catch(Exception e){
				 e.printStackTrace();
			 }
		 }
	 }
	 
	 public static void main(String[] args) throws IOException{
		 
		 Service service = new Service(9998);
		 
		 service.recieve();
	 }
	 
}

简单的TCP/UDP通信介绍到此,如果有什么不对的大家尽量指出,这样才能共同进步,对吗。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值