آموزش Socket در برنامه نویسی اندروید بخش دوم

سلام دوستان در این سری از آموزش های برنامه نویسی اندروید به آموزش Socket در برنامه نویسی اندروید بخش دوم می پردازیم در مطلب قبلی خیلی از دوستان اشاره کردن که برنامه به درستی کار نمی کند با بررسی که انجام دادم متوجه شدم در بیشتر مودم ها این قابلیت وجود ندارد به همین منظور امروز پست آموزشی دیگری را در همین رابطه ایجاد کردیم در ادامه با ما همراه باشید.
در این بار ما دو تا اپلیکیشن جدا درست می کنیم کی یکی از آنها سرور و دیگری Client می باشد و باید بروی دو گوشی یا Emulator اجرا شود البته دقت کنید که باید به یک مودم وصل شوند یا یکی از گوشی ها Hotspot شود و گوشی دیگری به آن وصل شود  و در هر صورت باید یک آیپی وصل شده باشند.
 
قبل از هرچیز وارد فایل AndroidManifest.xml شده دسترسی های زیر را اضافه کنید.

<uses-permission android:name="android.permission.INTERNET" > </uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" ></uses-permission>

حالا می خواهیم بخش سرور را پیاده سازی کنیم.
در بخش activity_main.xml کد های زیر را قرار دهید.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <TextView
        android:id="@+id/text2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="" >
    </TextView>
</LinearLayout>

همانطور که میبینید فقط شامل یک textView می باشد چون فقط در بخش سرور می خواهیم پیام رو از Client دریافت کنیم.
سپس یک فایل به نام Server.java ایجاد کنید.

package ir.programchi;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;
public class Server extends Activity {
	private ServerSocket serverSocket;
	Handler updateConversationHandler;
	Thread serverThread = null;
	private TextView text;
	public static final int SERVERPORT = 6000;
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		text = (TextView) findViewById(R.id.text2);
		updateConversationHandler = new Handler();
		this.serverThread = new Thread(new ServerThread());
		this.serverThread.start();
	}
	@Override
	protected void onStop() {
		super.onStop();
		try {
			serverSocket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	class ServerThread implements Runnable {
		public void run() {
			Socket socket = null;
			try {
				serverSocket = new ServerSocket(SERVERPORT);
			} catch (IOException e) {
				e.printStackTrace();
			}
			while (!Thread.currentThread().isInterrupted()) {
				try {
					socket = serverSocket.accept();
					CommunicationThread commThread = new CommunicationThread(socket);
					new Thread(commThread).start();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	class CommunicationThread implements Runnable {
		private Socket clientSocket;
		private BufferedReader input;
		public CommunicationThread(Socket clientSocket) {
			this.clientSocket = clientSocket;
			try {
				this.input = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		public void run() {
			while (!Thread.currentThread().isInterrupted()) {
				try {
					String read = input.readLine();
					updateConversationHandler.post(new updateUIThread(read));
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	class updateUIThread implements Runnable {
		private String msg;
		public updateUIThread(String str) {
			this.msg = str;
		}
		@Override
		public void run() {
			text.setText(text.getText().toString()+"Client Says: "+ msg + "\n");
		}
	}
}

در بالا ما از serverSocket  استفاده کردیم serverSocket  برای ارتباط های Tcp و Udp استفاده می شود و به یک پورت گوش میدهد  (listen) یعنی پس به صورت معمول ما نیاز به آیپی نداریم و فقط کافی است به یک آیپی وصل شده باشیم خودش آیپی ادرس را به دست می آورد و در بالا ما از پورت 6000 استفاده کردیم شما باید این پورت را باز کنید در ادامه نحوه باز کردن این پورت را به شما آموزش می دهیم البته دقت کنید کار کردن بروی پورت Emualtor کمی فرق دارد در ادامه توضیح خواهم داد.
حالا زمان این است اپلیکیشن دوم خودمان را که Client  باشد ایجاد کنیم.
دسترسی های مانند قبل است پس آنها را اضافه کنید.
یک فایل به نام activity_main.xml ایجاد کرده کدهای زیر را در  آن قرار دهید.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <EditText
        android:id="@+id/EditText01"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="JavaCodeGeeks" >
    </EditText>
    <Button
        android:id="@+id/myButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="send !" >
    </Button>
</LinearLayout>

شامل یک EditText برای دریافت ورودی از کاربر و یک دکمه برای ارسال داده است.
حالا یک فایل به نام Client.java ایجاد کرده و کد های زیر را در آن قرار دهید.

package ir.programchi;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
public class Client extends Activity {
	private Socket socket;
	private static final int SERVERPORT = 5000;
	private static final String SERVER_IP = "10.0.2.2";
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		new Thread(new ClientThread()).start();
	}
	public void onClick(View view) {
		try {
			EditText et = (EditText) findViewById(R.id.EditText01);
			String str = et.getText().toString();
			PrintWriter out = new PrintWriter(new BufferedWriter(
					new OutputStreamWriter(socket.getOutputStream())),
					true);
			out.println(str);
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	class ClientThread implements Runnable {
		@Override
		public void run() {
			try {
				InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
				socket = new Socket(serverAddr, SERVERPORT);
			} catch (UnknownHostException e1) {
				e1.printStackTrace();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
	}
}

در بالا اگر دقت کنید شماره port فرق می کند ! علت آن به خاطر این است که وقتی شما دو emualtor بروی یک pc اجرا می کنید هر Emulator به یک آیپی آدرس و پورت مشخص متصل می شود حالا چاره کا را باید اینطور که توضیح میدهم حل کنید در بالا نباید SERVER_IP اگر می خواهید در emulator اندروید استودیو استفاده کنید تغییر دهید این آیپی پیشفرض مجازی ساز اندروید استودیو است !
ابتدا برنامه اول را بروی Emulator اجرا کنید منظورم server است حالا cmd را باز کنید وارد پوشه adb شوید به صورت معمول در ریشه زیر نصب می شود.

C:\Users\نام کاربری شما\AppData\Local\Android\sdk\platform-tools

و در cmd کد زیر را قرار دهید.

cd C:\Users\نام کاربری شما\AppData\Local\Android\sdk\platform-tools

Enter را بزنید حالا کد زیر را اجرا کنید

adb devices

برای شما یک شماره پورت می نویسد port می نویسد حالا باید آن پورت را بر دارید و به بخش کد Server.java رفته و در قسمت SERVERPORT آن را وارد کنید این می شود پورت سرور شما حالا این Emualtor را نبندید برنامه دوم را در یک Emulator دیگه اجرا کنید سپس دوباره وارد دستور adb devices را اجرا کنید هم اکنون دو پورت به شما نمایش داده می شود پورت دومی را برداشته و وارد Client.java شده و در SERVERPORT قرار دهید حالا زمان redirect کردن یا PortForwarding است .
حالا در همان مسیری که هستید کد زیر را اجرا کنید. (در صورتی که با خطا مواجه شدید باید از قسمت programs and features باید Telent را فعال کنید به صورت معمول در بیشتر ویندوز ها این قابلیت خاموش است اگر نتونستید فعالش کنید در اینترنت یک سرچی بزنید)

telnet localhost 5554

Enter را زده اگر پیغام خطا مواجه شدید پورت را به 5037 تغییر دهید.

redir add tcp:5000:6000

در اینجا پورت 5000 را به 6000 redirect کردیم شما باید دو پورتی را که به دست آوردید در اینجا قرار دهید
تست برنامه !

حالا دوستانی که می خواهند روی دو گوشی تست کنن ! باید port Forwarding انجام دهند و پورت ها را در دو جا یکی قرار دهند.
 
این آموزش هم پایان رسید.
 
موفق و موید باشید.

مطالعه بیشتر