UDP通讯大致过程:
接收数据的大致步骤:
注意:TCP协议与UDP协议的端口是不冲突的
客户端
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
/** * 聊天室客户端 * @author Administrator * */
public class Client {
/* * java.net.Socket * 封装了TCP通讯,使用该类完成与服务器端的连接,并进行相应的通讯 */
private Socket socket;
/** * 构造方法用来初始化客户端 */
public Client() throws Exception{
try{
/* * 实例化Scoket时需要传入两个参数 * 1.服务器端的地址 * 2.服务器端的端口 * 通过地址找到服务端的计算机, * 端口则找到该计算机上的服务端应用程序 * * 实例化Socket的过程就是连接服务端的过程 * 连接不成功该构造方法会抛出异常 */
System.out.println("正在连接服务端...");
socket=new Socket("localhost",8088);
System.out.println("与服务端建立连接...");
}catch(Exception e){
throw e;
}
}
/** * 客户端启动方法 */
public void start(){
try{
/* * 先启动用于接受服务端发送过来的消息的线程 */
ServerHandler handler=new ServerHandler();
Thread t=new Thread(handler);
t.start();
/* * Socket提供了方法 * OutputStream getOutputStream() * 该方法客户获取一个字节输出流,通过该输出流写出的数据会发送至远端计算机 * 对于客户端这边而言远端是服务端 */
OutputStream out=socket.getOutputStream();
OutputStreamWriter osw=new OutputStreamWriter(out,"UTF-8");
PrintWriter pw=new PrintWriter(osw,true);
Scanner sc=new Scanner(System.in);
String message;
do{
System.out.println("请输入信息:");
message=sc.nextLine();
pw.println(message);
}while(true);
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
try{
Client client=new Client();
client.start();
}catch(Exception e){
e.printStackTrace();
}
}
/** * 该线程负责循环接收服务端发送过来的消息并输出到客户端的控制台 */
class ServerHandler implements Runnable{
public void run(){
try{
InputStream in=socket.getInputStream();
InputStreamReader isr=new InputStreamReader(in,"UTF-8");
BufferedReader br=new BufferedReader(isr);
String message=null;
while((message=br.readLine())!=null){
System.out.println(message);
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}
服务端
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
/** * 聊天室服务端 * @author Administrator * */
public class Server {
/* * java.net.ServerSocket * 运行在服务端的ServerSocket有两个作用 * 1:申请服务端口(客户端通过该端口与服务端建立连接) * 2:监听服务端口,等待客户端连接 * 一旦客户端连接则自动创建一个Socket实例用于与该客户端交互 */
private ServerSocket server;
/* * 该集合用于保存所有客户端的Socket */
private List<PrintWriter> allOut;
/** * 构造方法 * @throws Exception */
public Server() throws Exception{
try{
allOut=new ArrayList<PrintWriter>();
/* * 实例化SercerSocket需要指定服务端口, * 该端口不能与当前操作系统其他程序申请的端口冲突,否则会抛出端口被占用异常 */
server=new ServerSocket(8088);
}catch(Exception e){
throw e;
}
}
/** * 将给定的输出流存入共享集合 * @param Out */
private synchronized void addOut(PrintWriter out){
allOut.add(out);
}
/** * 将给定的输出流从共享集合中删除 * @param out */
private synchronized void removeOut(PrintWriter out){
allOut.remove(out);
}
/** * 将给定的消息发送给所有客户端 * @param message */
private synchronized void sendMessage(String message){
for(PrintWriter out:allOut){
out.println(message);
}
}
/** * 启动方法 */
public void start(){
try{
/* * ServerSocket提供了方法: * Socket accept(); * 该方法是一个阻塞方法,作用是监听ServerSocket开启的服务端口, * 知道一个客户端通过该端口连接,该方法才会解除阻塞, * 并返回一个Socket实例,通过该Socket实例与刚刚建立连接的客户端进行通讯 */
while(true){
System.out.println("等待客户端连接...");
Socket socket=server.accept();
System.out.println("一个客户端连接了...");
/* * 当一个客户端连接后,启动一个线程来处理与该客户端的交互工作 */
ClientHandler handler=new ClientHandler(socket);
Thread t=new Thread(handler);
t.start();
}
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
try{
Server server=new Server();
server.start();
}catch(Exception e){
e.printStackTrace();
}
}
/** * 该线程负责与指定的客户端进行交互 */
class ClientHandler implements Runnable{
/* * 当前线程负责与指定客户端交互的Socket */
private Socket socket;
//客户端的地址信息
private String host;
public ClientHandler(Socket socket){
this.socket=socket;
/* * 通过socket获取远程计算机地址信息 * 对于服务端而言,远程计算机就是客户端 */
InetAddress address=socket.getInetAddress();
//获取远端计算机IP
host=address.getHostAddress();
}
public void run(){
PrintWriter pw=null;
try{
sendMessage(host+"上线了!");
/* * 通过Socket创建输出流,用于将消息发送给客户端 */
OutputStream out=socket.getOutputStream();
OutputStreamWriter osw=new OutputStreamWriter(out,"UTF-8");
pw=new PrintWriter(osw,true);
//将该客户端的输出流存入共享集合
addOut(pw);
/* * 通过Socket创建输入流,用于读取客户端发来的消息 */
InputStream in=socket.getInputStream();
InputStreamReader isr=new InputStreamReader(in,"UTF-8");
BufferedReader br=new BufferedReader(isr);
String message=null;
/* * br.readLine读取客户端发送过来的一行字符串时, * 客户端断开连接时,由于客户端所在系统不同, * 这里readLine方法的执行结果也不相同: * 当windows的客户端断开连接时,readLine方法会直接抛出异常 * 当linux的客户端断开连接时,readLine方法会返回null */
while((message=br.readLine())!=null){
System.out.println(host+"说:"+message);
//转发给所有客户端
sendMessage(host+"说:"+message);
}
}catch(Exception e){
//e.printStackTrace();
}finally{
//客户端下线后从共享集合删除输出流
removeOut(pw);
//客户端与服务端断开连接
System.out.println(host+"下线了!");
try{
socket.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
}
客户端
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/** * UDP通讯的客户端 * @author Administrator * */
public class Client {
public static void main(String[] args) {
try{
//1
DatagramSocket socket=new DatagramSocket();
//2
String message="哟哟切克闹!";
byte[] data=message.getBytes("UTF-8");
//3
InetAddress address=InetAddress.getByName("localhost");
int port=8088;
//4
DatagramPacket packet=new DatagramPacket(data,data.length,address,port);
//5
socket.send(packet);
/* * 接收服务端发送回来的消息 */
data=new byte[100];
packet=new DatagramPacket(data,data.length);
/* * 3 * 该方法是一个阻塞方法,直到远程计算机发送数据过来为止, * 该方法才会解除阻塞,并将数据等信息设置到接收用的包中 */
socket.receive(packet);
/* * 4 * 下面的方法可以获取包中的数组,这个数组就是上边定义的data(看不到数组的情况下) * packet.getData(); * * packet.getLength() * 获取本次接收到的数据的长度 */
message=new String(data,0,packet.getLength(),"UTF-8");
System.out.println("服务端说:"+message);
}catch(Exception e){
e.printStackTrace();
}
}
}
服务端
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/** * UDP通讯的服务端 * @author Administrator * */
public class Server {
public static void main(String[] args) {
try{
//1
DatagramSocket socket=new DatagramSocket(8088);
//2
byte[] data=new byte[100];
DatagramPacket packet=new DatagramPacket(data,data.length);
/* * 3 * 该方法是一个阻塞方法,直到远程计算机发送数据过来为止, * 该方法才会解除阻塞,并将数据等信息设置到接收用的包中 */
socket.receive(packet);
/* * 4 * 下面的方法可以获取包中的数组,这个数组就是上边定义的data(看不到数组的情况下) * packet.getData(); * * packet.getLength() * 获取本次接收到的数据的长度 */
String message=new String(data,0,packet.getLength(),"UTF-8");
System.out.println("客户端说:"+message);
/* * 服务端回复客户端 */
//2
message="煎饼果子来一套!";
data=message.getBytes("UTF-8");
//3 通过接收包得到远程计算机地址,端口信息
InetAddress address=packet.getAddress();
int port=packet.getPort();
//4
packet=new DatagramPacket(data,data.length,address,port);
//5
socket.send(packet);
}catch(Exception e){
e.printStackTrace();
}
}
}