我们知道TCP是一种基于流的协议,基于TCP的聊天代码的编写需要分别编写服务器端和客户端,Java进行TCP编程时,需要使用Socket模型:
服务器端用ServerSocket监听指定端口;用accept()接收连接并返回Socket实例;
客户端使用Socket(InetAddress, port)连接服务器;
双方通过Socket打开InputStream/OutputStream读写数据;
和TCP编程相比,UDP没有创建连接,数据包也是一次收发一个,所以没有流的概念。
在Java中使用UDP编程,仍然需要使用Socket,因为应用程序在使用UDP时必须指定网络接口(IP地址)和端口号。注意:UDP端口和TCP端口虽然都使用0~65535,但他们是两套独立的端口,即一个应用程序用TCP占用了端口1234,不影响另一个应用程序用UDP占用端口1234。
基于UDP的聊天程序分别为先收后发和先发后收,他们的代码实现大致相同,只是接受和发送的顺序不同,UDP的使用也需要监听指定的端口。Java提供了DatagramSocket来实现这个功能,
需要创建两个DatagramSocket对象(例如名为sendPacket、receivePacket)
顾名思义,这两个包分别用来发送数据和接受数据,
在发送的过程中,需要将控制台的输入(字符串类型)转化为字节数组,再使用sendPacket的setData()方法将字节数组添加进去,再通过创建的DatagramSocket的对象(socket)的send方法发送(需要将senPacket作为send方法的参数)
在接收的过程中,通过创建的DatagramSocket的对象(socket)的receive方法接收(需要将receivePacket作为receive方法的参数),通过DatagramPacket返回的 receivepacket.getOffset()和packet.getLength()确定数据在缓冲区的起止位置,再与receivePacket.getData()一起作为参数传入创建的String对象的方法中
它们的代码分别如下:
package com.gjh.chat;
import java.io.ObjectInputStream.GetField;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.util.Scanner;
public class Text01 {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
try(DatagramSocket socket=new DatagramSocket(8080);){
DatagramPacket sendPacket=new DatagramPacket(new byte[1024], 1024,
new InetSocketAddress("192.168.254.174",7070));
DatagramPacket receivePacket=new DatagramPacket(new byte[1024], 1024);
System.out.print("你说:");
String word=input.nextLine();
sendPacket.setData(word.getBytes());
socket.send(sendPacket);
socket.receive(receivePacket);
String receive=new String(receivePacket.getData(),
receivePacket.getOffset(),receivePacket.getLength());
System.out.println("ta说:"+receive);
}catch (SocketException e) {
e.printStackTrace();
}catch (Exception e) {
e.printStackTrace();
}
}
}
package com.gjh.chat;
import java.io.ObjectInputStream.GetField;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.util.Scanner;
public class Text02 {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
try(DatagramSocket socket=new DatagramSocket(7070);){
DatagramPacket sendPacket=new DatagramPacket(new byte[1024], 1024,
new InetSocketAddress("192.168.254.174",8080));
DatagramPacket receivePacket=new DatagramPacket(new byte[1024], 1024);
socket.receive(receivePacket);
String receive=new String(receivePacket.getData(),
receivePacket.getOffset(),receivePacket.getLength());
System.out.println("ta说:"+receive);
System.out.print("你说:");
String word=input.nextLine();
sendPacket.setData(word.getBytes());
socket.send(sendPacket);
}catch (SocketException e) {
e.printStackTrace();
}catch (Exception e) {
e.printStackTrace();
}
}
}
在需要不断交互的情况下,可以将接收和发送的代码块放入while(true) { }中
也可以给接收和发送的字符串加上和结束标志的equals判断,这样便可以实现在输出结束标志的情况下,代码执行结束
部分代码如下:
while(true) {
System.out.print("你说:");
String word=input.nextLine();
if(word.equals("over")) {
System.out.println("你已退出聊天......");
break;
}
sendPacket.setData(word.getBytes());
socket.send(sendPacket);
socket.receive(receivePacket);
String receive=new String(receivePacket.getData(),
receivePacket.getOffset(),receivePacket.getLength());
if(receive.equals("over")) {
System.out.println("对方已退出聊天.....");
break;
}
System.out.println("ta说:"+receive);
}