ネットワークプログラミング
UDPネットワークプログラミング+ IO +マルチスレッド---->チャットルーム
UDPは非接続プロトコルです。送信元と端末は、データを送信する前に接続を確立しません。送信する場合は、アプリケーションからデータを取得して、できるだけ早くネットワークにスローします。「ping」コマンドを使用して、2つのホスト間のTCP / IP通信が正常かどうかをテストすることがよくあります。実際、「ping」コマンドの原則は、UDPデータパケットを他のホストに送信し、次に他のホストに送信することです。データパケットの受信を確認し、到着した情報を時間内にフィードバックし、ネットワークに接続します。
アイデア:UDPは、一方向のデータ送信、つまり1つの送信者と1つの受信者を実現します。チャットでは、メッセージを両方向に送信する必要があります。メッセージの送信と受信をそれぞれ実装する2つのクラスを記述し、それらにRunnableインターフェイスを実装させることで、チャット中にメッセージを送信および受信するスレッドが同時に実行されるようにすることができます。
ソケットソケット
送信者クラス
package SocketProgramming;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
//UDP消息发送不需要链接服务器
//发送端
public class TalkSend implements Runnable{
//建立一个Socket
DatagramSocket socket = null;
//IO流
BufferedReader reader = null;
//发出端口和接收目标的接收端口
private int fromPort;
private int toPort;
//接收目标IP
private String toIP;
public TalkSend(int fromPort, String toIP, int toPort) {
this.fromPort = fromPort;
this.toIP = toIP;
this.toPort = toPort;
try {
socket = new DatagramSocket(fromPort);
//控制台读取文字 System.in
reader = new BufferedReader(new InputStreamReader(System.in));
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true){
try {
//读入数据
String data = reader.readLine();
//转为字节流
byte[] datas = data.getBytes();
//数据包:数据,数据长度,发送给谁(IP加端口)
DatagramPacket packet = new DatagramPacket(datas,0,datas.length,
new InetSocketAddress(this.toIP,this.toPort));
//发送包
socket.send(packet);
//trim()去空格
if (data.trim().equals("bye")){
break;
}
}catch (Exception e){
e.printStackTrace();
}
}
//程序结束记得先断开连接释放系统资源
socket.close();
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
レシーバークラス
package SocketProgramming;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
//接收端
public class TalkReceive implements Runnable{
//建立一个Socket
DatagramSocket socket = null;
//接收者的端口
private int port;
//标记发送者的名字
private String msgFrom;
public TalkReceive(int port,String msgFrom) {
this.port = port;
this.msgFrom = msgFrom;
try {
socket = new DatagramSocket(port);
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void run() {
while (true){
try {
//准备接收数据包
byte[] container = new byte[1024];
DatagramPacket packet = new DatagramPacket(container, 0 ,container.length);
socket.receive(packet);//阻塞式接收包裹
//读取数据
byte[] data = packet.getData();
String receiveData = new String(data, 0 ,data.length);
System.out.println(msgFrom + ":"+receiveData);
if (receiveData.trim().equals("bye")){
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
//断开连接
socket.close();
}
}
2つのテストクラスは、2人のチャットをシミュレートします
package SocketProgramming;
//学生和老师通信,两者都是接收方和发送方,调用两个线程接收和发送
public class TestTalkStudent {
public static void main(String[] args) {
//开启两个线程
new Thread(new TalkReceive(8888,"老师")).start();
new Thread(new TalkSend(7777,"localhost",9999)).start();
}
}
package SocketProgramming;
public class TestTalkTeacher {
public static void main(String[] args) {
//开启两个线程
new Thread(new TalkReceive(9999,"学生")).start();
new Thread(new TalkSend(5555,"localhost",8888)).start();
}
}
運転結果
実際、qqとほぼ同じです。2人が同時にオンラインチャットをしていて、1人がオフラインのときにオフラインメッセージを受信でき、2人が同時にいるとバイプログラムが終了します。
なぜclose()
新しいJavaストリームオブジェクトを作成すると、対応するクラスのインスタンスオブジェクトだけがコンピュータメモリに作成されるわけではありません。さらに、ファイルハンドル、ポート、データベース接続などの対応するシステムリソースも占有します。メモリ内のインスタンスオブジェクトへの参照がない場合、Javaガベージコレクタは対応する戦略に従って自動的にそれを再利用しますが、システムリソースを解放することはできません。したがって、javaストリームオブジェクトを解放するには、close()メソッドをアクティブに呼び出す必要があります。java7の後、try-with-resourcesステートメントを使用してjavaストリームオブジェクトを解放できるため、特にfinally節で、面倒なtry-catch-finallyステートメントを回避できます。close()メソッドも例外をスローします。
IOストリーミングには集中的な学習が必要です!