Client端:
Client端:
activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.and_sv.MainActivity" >
<EditText
android:id="@+id/edtname"
android:layout_width="100dp"
android:layout_height="wrap_content" >
</EditText>
<EditText
android:id="@+id/edttext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/edtname"
android:layout_marginLeft="20dp"
android:layout_toRightOf="@+id/edtname"
android:ems="10" >
</EditText>
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="@+id/edttext"
android:layout_below="@+id/edttext"
android:text="送出" />
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/edtname"
android:layout_below="@+id/button1" />
</RelativeLayout>
MainActivity.java:
public class MainActivity extends Activity {
private EditText edtname,edttext;
private TextView textview1;
private Button button1;
String tmp; // 暫存文字訊息
Socket clientSocket;
public static Handler mHandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edtname = (EditText)findViewById(R.id.edtname);
edttext = (EditText)findViewById(R.id.edttext);
button1 = (Button)findViewById(R.id.button1);
textview1 = (TextView)findViewById(R.id.textView1);
button1.setOnClickListener(btnlistener);
Thread t = new Thread(readData);
// 啟動執行緒
t.start();
}
private OnClickListener btnlistener = new Button.OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(clientSocket.isConnected()){
BufferedWriter bw;
try {
// 取得網路輸出串流
bw = new BufferedWriter( new OutputStreamWriter(clientSocket.getOutputStream()));
// 寫入訊息
bw.write(edtname.getText()+":"+edttext.getText()+"\n");
// 立即發送
bw.flush();
} catch (IOException e) {
}
// 將文字方塊清空
edttext.setText("");
}
}
};
// 顯示更新訊息
private Runnable updateText = new Runnable() {
public void run() {
// 加入新訊息並換行
textview1.append(tmp + "\n");
}
};
// 取得網路資料
private Runnable readData = new Runnable() {
public void run() {
// server端的IP
InetAddress serverIp;
try {
// 以內定(本機電腦端)IP為Server端
serverIp = InetAddress.getByName("10.0.2.2");
int serverPort = 5050;
clientSocket = new Socket(serverIp, serverPort);
// 取得網路輸入串流
BufferedReader br = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
// 當連線後
while (clientSocket.isConnected()) {
// 取得網路訊息
tmp = br.readLine();
// 如果不是空訊息則
if(tmp!=null)
// 顯示新的訊息
mHandler.post(updateText);
}
} catch (IOException e) {
}
}
};
}
Server端:
public class Server {
private static int serverport = 5050;
private static ServerSocket serverSocket;
private static int count=0;
// 用串列來儲存每個client
private static ArrayList players=new ArrayList();
// 程式進入點
public static void main(String[] args) {
try {
serverSocket = new ServerSocket(serverport);
System.out.println("Server is start.");
// 顯示等待客戶端連接
System.out.println("Waiting for clinet connect");
// 當Server運作中時
while (!serverSocket.isClosed()) {
// 呼叫等待接受客戶端連接
waitNewPlayer();
}
} catch (IOException e) {
System.out.println("Server Socket ERROR");
}
}
// 等待接受客戶端連接
public static void waitNewPlayer() {
try {
Socket socket = serverSocket.accept();
++count;
System.out.println("現在使用者個數:"+count);
// 呼叫創造新的使用者
createNewPlayer(socket);
} catch (IOException e) {
}
}
// 創造新的使用者
public static void createNewPlayer(final Socket socket) throws IOException {
// 以新的執行緒來執行
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
// 增加新的使用者
players.add(socket);
// 取得網路串流
BufferedReader br = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
// 當Socket已連接時連續執行
while (socket.isConnected()) {
// 取得網路串流的訊息
String msg= br.readLine();
if(msg==null){
System.out.println("Client Disconnected!");
break;
}
//輸出訊息
System.out.println(msg);
// 廣播訊息給其它的客戶端
castMsg(msg);
}
} catch (IOException e) {
e.getStackTrace();
}
finally{
// 移除客戶端
players.remove(socket);
--count;
System.out.println("現在使用者個數:"+count);
}
}
});
// 啟動執行緒
t.start();
}
// 廣播訊息給其它的客戶端
public static void castMsg(String Msg){
// 創造socket陣列
Socket[] ps=new Socket[players.size()];
// 將players轉換成陣列存入ps
players.toArray(ps);
// 走訪ps中的每一個元素
for (Socket socket : ps ) {
try {
// 創造網路輸出串流
BufferedWriter bw;
bw = new BufferedWriter( new OutputStreamWriter(socket.getOutputStream()));
// 寫入訊息到串流
bw.write(Msg+"\n");
// 立即發送
bw.flush();
} catch (IOException e) {
}
}
}
}
PS:因為要持續的更新Textview所以必須使用new Handler().post(runnable)
在Android裡只有(Main Thread或UI Thread)主線程負責UI的操作或事件,子線程不可以插手有關UI的事,但是可以透過子線程去處理複雜的事情,再透過Handler去通知主線程更新UI
您好
回覆刪除我使用您的程式來學習Android Socket
然而當我使用Android 8.0手機直接app時,可以順利連線,但是要送出內容時,app就閃退了,請問如何解決?謝謝您。
你好,請問你的Server端程式是放在哪裡呢?
刪除因為我這支server端程式是放在自己的電腦,serverIp = InetAddress.getByName("10.0.2.2");
10.0.2.2是local端的ip,所以外面是連不進去的。還有server端程式要保持運作
我的也在案出送出後會閃退,可以用虛擬IP嗎?PORT需要開啟嗎
回覆刪除+1 閃退
回覆刪除遇到相同問題, 改了幾個地方, 供參考
回覆刪除private View.OnClickListener btnlistener = new Button.OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(clientSocket!=null && clientSocket.isConnected()){
Thread t = new Thread(sendData);
t.start();
// 將文字方塊清空
edttext.setText("");
}
}
};
private Runnable sendData = new Runnable() {
public void run() {
BufferedWriter bw;
try {
// 取得網路輸出串流
bw = new BufferedWriter( new OutputStreamWriter(clientSocket.getOutputStream()));
// 寫入訊息
bw.write(edtname.getText()+":"+edttext.getText()+"\n");
// 立即發送
bw.flush();
} catch (IOException e) {
}
}
};