java中的套接字初探

TCP和UDP

TCP和UDP他们在OSI分层中都位于传输层,为应用层提供支持。TCP属于面向连接的网络传输协议,客户端和服务器端需要建立稳定的连接,才能相互传输数据。而UDP是面向无连接的网络传输协议,客户端和服务器端不需要建立连接,客户端发送出去的数据包不管对方是否存在,都可以发送。

TCP

TCPTransmission Control Protocol)传输控制协议属于一种稳定可靠的连接方式,客户端与服务器在建立连接之前需要进行三次握手。连接虽然稳定,但是由于数据传输过程复杂,导致传输效率较UDP低很多。通常运用在数据要求准确的场景下,如文件传输、网页显示、邮件传递等等。在javaTCP通过Socket和ServerSocket两个类来实现TCP的功能。

1.TCP客户端Socket
//客户端类
public class TestSocketclient {
	//构造方法
	public TestSocketclient(String ip,int port){
		try {
			@SuppressWarnings("resource")
			Socket socket = new Socket(ip,port);//指明服务器ip和端口号
			//向服务器发送消息
			String data = "hello server";
			OutputStream os = socket.getOutputStream();//输出流就是向服务器发送数据的流
			os.write(data.getBytes());
			
			//接收来自服务器的消息
			InputStream is = socket.getInputStream();//输入流就是接收来自服务器数据的流
			byte[] serverinfo = new byte[1024];
			int n = -1;
			while((n=is.read(serverinfo))!=-1){
				String string = new String(serverinfo,0,n);
				System.out.println(string);
			}
			
			os.close();
			is.close();
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	//启动方法,应该让服务器端先启动
	public static void main(String[] args) {
		try {
			new TestSocketclient(InetAddress.getLocalHost().getHostAddress(),8888);
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}
	}
}
2.TCP服务端ServerSocket
//服务器端
public class TestServerSocket {
	//构造方法
	public TestServerSocket(int port){
		try {
			ServerSocket ss = new ServerSocket(port);//监听端口
			//接收来自客户端的数据,该方法accept()是阻塞方法,直到接到请求才往下执行。
			Socket accept = ss.accept();
			InputStream is = accept.getInputStream();
			byte[] packet = new byte[1024];
			int n = is.read(packet);
			String string = new String(packet,0,n);
			System.out.println(string);
			//向客户端发送消息
			OutputStream os = accept.getOutputStream();
			os.write("hello client".getBytes());
			
			os.close();
			is.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	//启动方法
	public static void main(String[] args) {
		new TestServerSocket(8888);
	}
}

UDP

UDPUser Datagram Protocol)用户数据报协议属于一种不太稳定的数据传输协议,往往在传输过程中容易丢失数据报,但不会丢失太多,不影响总体数据的完整性。看上去UDP既然不稳定,还丢失数据,为什么还保留至今,没有被摒弃?那是因为它具有非常不凡的传输效率。应用也非常广泛,如网络游戏,虽不是所有数据都是UDP(如玩家属性)但其分量占比很大、QQ聊天工具、实时视频通话、视频会议等等。在java中使用DatagramSocket类实现UDP功能。

1.UDP客户端
//客户端
public class TestUDPclient {
	//构造方法
	public TestUDPclient(String ip,int port){
		
		try {
			//客户端不用在socket上指明ip和port
			DatagramSocket ds = new DatagramSocket();
			
			byte[] buf = "nihao 服务器".getBytes();
			int length = buf.length-4;//必须是绑定数据的大小,不能大于,可以小于,不能为负
			InetAddress address = InetAddress.getByName(ip);
			//在数据报上指明服务器的ip和port
			DatagramPacket dp = new DatagramPacket(buf,length, address, port);
			//发送数据
			ds.send(dp);
			//关闭套接字
			ds.close();
		} catch (SocketException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	//启动方法
	public static void main(String[] args) {
		new TestUDPclient("localhost",7777);
	}
}
2.UDP服务器端
//服务器端
public class TestUDPServer {
	//构造方法
	public TestUDPServer(int port){
		try {
			
			DatagramSocket ps = new DatagramSocket(port);//监听port端口是否有请求
			byte[] b= new byte[1024];
			DatagramPacket pd = new DatagramPacket(b, 1024);//准备一个空包接收数据用
			//接收数据
			ps.receive(pd);
			//得到数据并打印
			byte[] data = pd.getData();
			System.out.println(new String(data,0,data.length));
			//关闭套接字
			ps.close();
		} catch (Exception e) {
		}
	}
	//启动方法
	public static void main(String[] args) {
		new TestUDPServer(7777);
	}

}
3.补充

UDP在用DatagramSocket类实现时客户端和服务器端都是使用相同的类,他们是通过是否配置了端口号和IP来区分服务器和客户端的。只要配置了端口和IP的DatagramSocket都可以充当服务器端。但是同一IP地址下端口号不能一样,不然会报端口占用的异常。谁先接收数据谁先启动,以下是举例说明:

  • 客户端
public class TestUDPclient {
	
	public TestUDPclient(String ip,int port){
		
		try {
			//作为端口号为8888的服务器端
			DatagramSocket ds = new DatagramSocket(8888);
			
			byte[] buf = "nihao 服务器".getBytes();
			int length = buf.length;
			InetAddress address = InetAddress.getByName(ip);
			DatagramPacket dp = new DatagramPacket(buf,length, address, port);
			
			ds.send(dp);
			//发送后再来接收数据
			DatagramPacket dp2 = new DatagramPacket(new byte[1024], 1024);
			ds.receive(dp2);
			byte[] data = dp2.getData();
			System.out.println(new String(data,0,data.length));
			
			ds.close();
		} catch (SocketException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		new TestUDPclient("localhost",7777);
	}
}
  • 服务器端
public class TestUDPServer {
	
	public TestUDPServer(int port){
		try {
			//作为端口号为7777的服务器端
			DatagramSocket ps = new DatagramSocket(port);
			byte[] b= new byte[1024];
			DatagramPacket pd = new DatagramPacket(b, 1024);
			
			ps.receive(pd);
			
			byte[] data = pd.getData();
			System.out.println(new String(data,0,data.length));
			//接收完数据再发送,发送给本地端口号为8888的服务器端
			DatagramPacket dp2 = new DatagramPacket("nihao".getBytes(),5,InetAddress.getByName("localhost"),8888);
			ps.send(dp2);
			
			ps.close();
		} catch (Exception e) {
		}
	}
	
	public static void main(String[] args) {
		new TestUDPServer(7777);
	}

}

进一步说明,其实每个应用在启动后,如果应用自己没有指定端口号,系统会自动为其分配一个端口号。但是我们在编程的时候出于方便,传输两端约定成俗,各自指定一个端口号。在客户端通过数据报DatagramPacket发送给服务器端,服务器接收到后,可以直接从数据报中获取客户端的端口号。代码如下

//服务器端
public class TestUDPServer {
	
	public TestUDPServer(int port){
		try {
			DatagramSocket ps = new DatagramSocket(port);
			byte[] b= new byte[1024];
			DatagramPacket pd = new DatagramPacket(b, 1024);
			
			ps.receive(pd);
			
			byte[] data = pd.getData();
			System.out.println(new String(data,0,data.length));
			System.out.println("服务器端接收到的客户端的端口号:"+pd.getPort());
			DatagramPacket dp2 = new DatagramPacket("nihao".getBytes(),5,InetAddress.getByName("localhost"),pd.getPort());
			ps.send(dp2);
			
			ps.close();
		} catch (Exception e) {
		}
	}
	
	public static void main(String[] args) {
		new TestUDPServer(7777);
	}

}




//客户端
public class TestUDPclient {
	
	public TestUDPclient(String ip,int port){
		
		try {
			DatagramSocket ds = new DatagramSocket();
			
			byte[] buf = "nihao 服务器".getBytes();
			int length = buf.length;//必须是数据的大小,不能大于,可以小于,不能为负
			InetAddress address = InetAddress.getByName(ip);
			DatagramPacket dp = new DatagramPacket(buf,length, address, port);
			
			ds.send(dp);
			
			DatagramPacket dp2 = new DatagramPacket(new byte[1024], 1024);
			ds.receive(dp2);
			byte[] data = dp2.getData();
			System.out.println(new String(data,0,data.length));
			System.out.println("客户端接收到的服务器端的端口号:"+dp2.getPort());
			ds.close();
		} catch (SocketException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		new TestUDPclient("localhost",7777);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值