[アンドロイド]ソケットプログラム
ソケットプログラム
コンセント
HTTP通信プログラムは,サーバとのデータ交換に最もよく用いられるが,サーバとクライアント間の接続が継続できないため,リアルタイムサーバプッシュは実現できない.
前述したように,HTTP通信プログラムは,リアルタイムサーバプッシュを実施する必要がある場所では利用できない.これは,サーバとのデータ交換後,応答終了時に自動的に接続が切断されるためである.これを「HTTPの無状態」と呼ぶ.もちろん、クライアントは、必要に応じていつでも再接続してデータを受信することができます.ただし、リアルタイムサーバプッシュは、サーバ側でデータが発生した場合にクライアントにデータを送信する必要があり、クライアントは接続解除状態にあり、クライアントが再接続を要求しない限り転送できません.
リアルタイムサーバプッシュが必要な典型的な例は、チャットプログラムである.相手が送信したメッセージはサーバに送信し、その瞬間にクライアント(または)にリアルタイムで送信しなければならないが、HTTPは接続を継続できないため、サーバはクライアントにデータを送信できない.最終的には、チャットなどのリアルタイムサーバプッシュを実現するには、クライアントとサーバ間の接続を維持する必要があるため、ソケットプログラムが必要です.
ソケットプログラムは、クライアントがサーバに接続要求を発行し、接続が完了した後も実行を継続する構造であるため、クライアントまたはサーバでデータが発生するたびに、この接続を使用してリアルタイムでデータを転送することができる.
ソケットクラス
タスク#タスク#
HTTP通信と同様に,ソケットプログラムの作成にはINTERNETスーパータスクが必要である.<uses-permission android:name="android.permission.INTERNET" />
カテゴリ
サーバとスロットの接続には、SocketクラスとInetSocketAddressクラスが使用されます.InteSocketAddressは、接続サーバ情報を表すクラスで、作成者にIPアドレスとポート番号を指定します.InetSocketAddressで表されるサーバの場合、接続要求はSocketクラスのconnect()関数呼び出しで完了し、connect()関数パラメータとしてInetSocketAddressオブジェクトとタイムアウト時間を指定できます.// 소켓 객체 생성
socket = Socket()
// InetSocketAddress 생성자에 서버의 IP와 포트번호를 인자로 주고 객체 생성
val remoteAddr = InetSocketAddress(serverIp, serverPort)
// connect 메서드를 사용하고 InetSocketAddress 객체와 타임아웃 시간 지정
socket?.connect(remoteAddr, 10 * 1000)
Socketクラスに接続されているサーバにデータを送信するには、IOオブジェクトを作成する必要があります.// getOutputStream() 메서드를 사용하여 소켓의 output stream을 획득하고
// 그것을 BufferedOutputStream에 연결
bout = BufferedOutputStream(socket?.getOutputStream())
// getInputStream() 메서드를 사용하여 소켓의 input stream을 획득하고
// 그것을 BufferedInputStream에 연결
bin = BufferedInputStream(socket?.getInputStream())
// 데이터를 송신하기 위해 BufferedOutputStream의 write 메서드를 사용
// 매개변수로 전송하고자 하는 데이터 지정
bout.write((msg.obj as String).toByteArray())
bout.flush()
// 데이터를 수신하기 위해 BufferedInputStream의 read 메서드를 사용
var message: String? = null
val size = bin.read(buffer)
if(size > 0) {
message = String(buffer, 0, size, charset("utf-8"))
}
ソケットオブジェクトを使用して、接続されたサーバとデータを送信します.getOutputStream(), socket.getInputStream()構文でIOオブジェクトを取得します.このIOオブジェクトを使用して、必要に応じてデータを送信または受信します.送信データはwrite()メソッド,受信データはread()メソッドを用いる.
コンセントを作成する際の注意点
ソケット通信を行うには、サーバに接続し、接続されたサーバとデータを送信および受信する必要があります.しかし、これらはすべてスレッドで処理する必要があります.データの送受信と接続には、ネットワークがいつでもオフラインになっているため、完了するのに時間がかかる場合があります.したがって、スレッドとして処理しない場合、ANR(アクティブな場合の例)が発生する可能性があります.
もちろん、サービスコンポーネントで作成しても、接続とデータ送受信はスレッドで処理する必要があります.
ソケットプログラムの特性に応じて、サーバと長時間接続する必要があります.サービスが実行中にサーバとの接続に成功した場合、いつでも接続を切断する可能性があります.そのため、サーバの接続ステータスを特定し、接続に失敗したときに接続を維持するために、ある場所で接続を維持する必要があります.最終的には、サーバ接続部がスレッドとみなされ、接続されていない場合は、接続を続行する必要があります.
接続スレッド
簡単なサンプルコードは、isConnectedというboolean値を使用して、現在のサーバに接続するかどうかを示し、この値に基づいて再接続を試みます.// 소켓 생성 스레드
inner class SocketThread: Thread() {
override fun run() {
while(flagConnection) {
try {
// 연결이 안된 경우
if(!isConnected) {
// 소켓 객체 생성
socket = Socket()
// InetSocketAddress 생성자에 서버의 IP와 포트번호를 인자로 주고 객체 생성
val remoteAddr = InetSocketAddress(serverIp, serverPort)
// connect 메서드를 사용하고 InetSocketAddress 객체와 타임아웃 시간 지정
socket?.connect(remoteAddr, 10 * 1000)
// 코드....
} else { // 연결이 된 경우
SystemClock.sleep(10000)
}
} catch(e: Exception) {
// 소켓 연결 시 오류는 여러 가지가 존재합니다.
}
}
}
}
スレッドの読み込み
データはサーバから転送しなければ読み込めないため、read()メソッドを実行すると、サーバからデータを転送する前に下りは待機状態になり、実行されません.これらの読み込み動作は、次のようにスレッドとして扱われます.// 읽기 스레드
inner class ReadThread: Thread() {
override fun run() {
// Byte 배열 생성
var buffer = ByteArray(1024)
try {
// read 함수를 사용하여 데이터 수신
val size = bin?.read(buffer)
// 받아온 데이터의 크기가 0보다 크다면
if(size != null && size > 0) {
// read 후 업무 처리
}
} catch(e: IOException) {
}
}
}
書き込みスレッド
書き込み動作は、次のようにスレッドとして扱われます.次のコードは、アクティビティに書き込まれたコードです.書き込みデータは、メインスレッドによって管理されるビュー内のデータであるため、書き込みスレッドから直接ビューオブジェクトにアクセスすることはできません.最終的には、プライマリ・スレッドからビュー・データを取得し、書き込みスレッドのHandlerを使用してデータを転送し、サーバの構造記述プログラムに送信する必要があります.// 쓰기 스레드
inner class WriteThread: Thread() {
override fun run() {
// 현재 스레드에 Looper 초기화
Looper.prepare()
// 핸들러 생성
writeHandler = object: Handler(Looper.myLooper()!!) {
// 메세지 처리하기
override fun handleMessage(msg: Message) {
try {
// 전달된 메세지 객체를 String으로 형변환 후 ByteArray로 변경
// 그 후 write 메서드를 통해 데이터 전송
bout?.write((msg.obj as String).toByteArray())
bout?.flush()
// ....
} catch(e: Exception) {
}
}
}
// 메세지큐 작동
Looper.loop()
}
}
リファレンス
姜先生のAndroidプログラミング
間違った部分をコメントに書いたら修正します…!
Reference
この問題について([アンドロイド]ソケットプログラム), 我々は、より多くの情報をここで見つけました
https://velog.io/@changhee09/안드로이드-소켓-프로그램
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
<uses-permission android:name="android.permission.INTERNET" />
// 소켓 객체 생성
socket = Socket()
// InetSocketAddress 생성자에 서버의 IP와 포트번호를 인자로 주고 객체 생성
val remoteAddr = InetSocketAddress(serverIp, serverPort)
// connect 메서드를 사용하고 InetSocketAddress 객체와 타임아웃 시간 지정
socket?.connect(remoteAddr, 10 * 1000)
// getOutputStream() 메서드를 사용하여 소켓의 output stream을 획득하고
// 그것을 BufferedOutputStream에 연결
bout = BufferedOutputStream(socket?.getOutputStream())
// getInputStream() 메서드를 사용하여 소켓의 input stream을 획득하고
// 그것을 BufferedInputStream에 연결
bin = BufferedInputStream(socket?.getInputStream())
// 데이터를 송신하기 위해 BufferedOutputStream의 write 메서드를 사용
// 매개변수로 전송하고자 하는 데이터 지정
bout.write((msg.obj as String).toByteArray())
bout.flush()
// 데이터를 수신하기 위해 BufferedInputStream의 read 메서드를 사용
var message: String? = null
val size = bin.read(buffer)
if(size > 0) {
message = String(buffer, 0, size, charset("utf-8"))
}
// 소켓 생성 스레드
inner class SocketThread: Thread() {
override fun run() {
while(flagConnection) {
try {
// 연결이 안된 경우
if(!isConnected) {
// 소켓 객체 생성
socket = Socket()
// InetSocketAddress 생성자에 서버의 IP와 포트번호를 인자로 주고 객체 생성
val remoteAddr = InetSocketAddress(serverIp, serverPort)
// connect 메서드를 사용하고 InetSocketAddress 객체와 타임아웃 시간 지정
socket?.connect(remoteAddr, 10 * 1000)
// 코드....
} else { // 연결이 된 경우
SystemClock.sleep(10000)
}
} catch(e: Exception) {
// 소켓 연결 시 오류는 여러 가지가 존재합니다.
}
}
}
}
// 읽기 스레드
inner class ReadThread: Thread() {
override fun run() {
// Byte 배열 생성
var buffer = ByteArray(1024)
try {
// read 함수를 사용하여 데이터 수신
val size = bin?.read(buffer)
// 받아온 데이터의 크기가 0보다 크다면
if(size != null && size > 0) {
// read 후 업무 처리
}
} catch(e: IOException) {
}
}
}
// 쓰기 스레드
inner class WriteThread: Thread() {
override fun run() {
// 현재 스레드에 Looper 초기화
Looper.prepare()
// 핸들러 생성
writeHandler = object: Handler(Looper.myLooper()!!) {
// 메세지 처리하기
override fun handleMessage(msg: Message) {
try {
// 전달된 메세지 객체를 String으로 형변환 후 ByteArray로 변경
// 그 후 write 메서드를 통해 데이터 전송
bout?.write((msg.obj as String).toByteArray())
bout?.flush()
// ....
} catch(e: Exception) {
}
}
}
// 메세지큐 작동
Looper.loop()
}
}
Reference
この問題について([アンドロイド]ソケットプログラム), 我々は、より多くの情報をここで見つけました https://velog.io/@changhee09/안드로이드-소켓-프로그램テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol