Android socket 學習記錄 之 執行new socket(ip, port)程式崩潰

來源:互聯網
上載者:User

標籤:socket   伺服器   線程   網路   

這段時間在學習Android的socket編程,我不是專做APP的,做的是bootloader、驅動、hal、framework這個線的,也就是系統搭建和功能最佳化設計。為了打通這整條線,為此學習了不少東西,今天把Android的socket學習記錄一下,以防止以後會出現這樣的低級錯誤。


我這裡是在極客學院的源碼基礎上做的自己的一些添加和修改,學習開始不就是先會修改麼,舉一反三,自然就很快學會了。由於看過視頻和資料後就迫不及待的按照自己的想法想做一個功能,但是遇到麻煩了,就是執行new socket(ip, port)程式崩潰的問題,怎麼找都找不到,代碼也看不出問題,頭大了快一天,最終還是被解決了,O(∩_∩)O。不過也慶幸找遇到這樣的問題,以後就不會因為這個問題而傷腦筋了。


下面記錄一下源碼和相關說明。

主要使用了兩個java檔案。

MainActivity.java:

<pre name="code" class="java">package com.jikexueyuan.mysocketclient;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.CompoundButton;import android.widget.EditText;import android.widget.TextView;import android.widget.ToggleButton;public class MainActivity extends Activity {EditText ip;EditText port;EditText editText;TextView text;ToggleButton connect;Button send;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ip = (EditText) findViewById(R.id.ip);port = (EditText) findViewById(R.id.port);editText = (EditText) findViewById(R.id.edit);text = (TextView) findViewById(R.id.text);send = (Button) findViewById(R.id.send);connect = (ToggleButton) findViewById(R.id.connect);connect.setOnCheckedChangeListener(new ToggleButtonCheckedChangeEvent());send.setOnClickListener(new ButtonClickEvent());ConnectClass.datainit(ip, port, editText, text, send, connect);//傳遞布局資料給類ConnectClasssend.setEnabled(false);}// ----------------------------------------------------清除按鈕、發送按鈕class ButtonClickEvent implements View.OnClickListener {public void onClick(View v) {if (v == send) {ConnectClass.send();}}}class ToggleButtonCheckedChangeEvent implementsToggleButton.OnCheckedChangeListener {@Overridepublic void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {if (buttonView == connect) {if (isChecked) {ConnectClass.connect(MainActivity.this);} else {ConnectClass.unconnect();}}}}}

這個主檔案沒什麼好說的,就是做一些初始化。相對於極客學院的code,我添加了ToggleButton按鈕,用於串連和斷開使用,另外還添加了一個連接埠設定視窗。布局檔案也貼出來。

activity_main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/container"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >    <LinearLayout        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:orientation="horizontal" >        <EditText            android:id="@+id/ip"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="1"            android:hint="輸入伺服器的IP地址"            android:text="192.168.0.55" >        </EditText>        <EditText            android:id="@+id/port"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="0.35"            android:hint="輸入伺服器的PORT"            android:text="2030" >        </EditText>        <ToggleButton            android:id="@+id/connect"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="串連"            android:textOff="@string/connect"            android:textOn="@string/unconnect" />    </LinearLayout>    <ScrollView        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:layout_weight="0.86" >        <TextView            android:id="@+id/text"            android:layout_width="fill_parent"            android:layout_height="fill_parent"            android:text="Ready..." />    </ScrollView>    <EditText        android:id="@+id/edit"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:hint="在這裡輸入內容" />    <Button        android:id="@+id/send"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:text="發送" /></LinearLayout>

重點是ConnectClass.java這個類檔案,源碼如下:

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span><pre name="code" class="cpp">package com.jikexueyuan.mysocketclient;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.net.Socket;import java.net.UnknownHostException;import android.content.Context;import android.os.AsyncTask;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;import android.widget.ToggleButton;public class ConnectClass {static Socket socket = null;static BufferedWriter writer = null;static BufferedReader reader = null;static EditText ip;static EditText port;static EditText editText;static TextView text;static Button send;static ToggleButton connect;public static void datainit(final EditText tIp, final EditText tPort, final EditText tEditText, final TextView tText, final Button tButton, final ToggleButton tToggleButton){ip = tIp;port = tPort;editText = tEditText;text = tText;send = tButton;connect = tToggleButton;}public static void connect(final Context tActivity) {AsyncTask<Void, String, Void> read = new AsyncTask<Void, String, Void>() {@Overrideprotected Void doInBackground(Void... arg0) {try {socket = new Socket(ip.getText().toString(), Integer.decode(port.getText().toString()));writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));//send.setEnabled(true);publishProgress("@success");} catch (UnknownHostException e1) {Toast.makeText(tActivity, "無法建立連結", Toast.LENGTH_SHORT).show();} catch (IOException e1) {Toast.makeText(tActivity, "無法建立連結", Toast.LENGTH_SHORT).show();}try {String line;while ((line = reader.readLine())!= null) {publishProgress(line);}} catch (IOException e) {e.printStackTrace();}return null;}@Overrideprotected void onProgressUpdate(String... values) {if (values[0].equals("@success")) {Toast.makeText(tActivity, "連結成功!", Toast.LENGTH_SHORT).show();send.setEnabled(true);}text.append("別人說:"+values[0]+"\n");super.onProgressUpdate(values);}};read.execute();}public static void unconnect() {try {writer.close();reader.close();socket.close();send.setEnabled(false);connect.setChecked(false);} catch (IOException e) {e.printStackTrace();}}public static void send() {try {text.append("我說:"+editText.getText().toString()+"\n");writer.write(editText.getText().toString()+"\n");writer.flush();editText.setText("");} catch (IOException e) {e.printStackTrace();}}}

這個檔案類,完成網路的串連,斷開,發送等功能。

這裡重點說明new socket這個函數的使用,也就是標題的崩潰問題原因。進過Google發現,要使用new socket這個函數,不能在主線程ui中使用,否則就會報錯崩潰,必須使用分線程來調用new socket函數進行網路操作,上面用的是AsyncTask非同步線程,當然其他線程也是可以的。

另外還有一個原因會導致崩潰,就是網路許可權,設定檔中一定要有這句<uses-permission android:name="android.permission.INTERNET"/>。

服務端我用的是Linux系統下的,源碼如下:

/* File Name: server.c */  #include<stdio.h>  #include<stdlib.h>  #include<string.h>  #include<errno.h>  #include<sys/types.h>  #include<sys/socket.h>  #include<netinet/in.h>  #define DEFAULT_PORT 2030  #define MAXLINE 4096  int main(int argc, char** argv)  {      int    socket_fd, connect_fd;      struct sockaddr_in     servaddr;      char    buff[4096];      int     n;      //初始化Socket      if( (socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){      printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);      exit(0);      }      //初始化      memset(&servaddr, 0, sizeof(servaddr));      servaddr.sin_family = AF_INET;      servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//IP地址設定成INADDR_ANY,讓系統自動擷取原生IP地址。      servaddr.sin_port = htons(DEFAULT_PORT);//設定的連接埠為DEFAULT_PORT        //將本地地址綁定到所建立的通訊端上      if( bind(socket_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){      printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);      exit(0);      }      //開始監聽是否有用戶端串連      if( listen(socket_fd, 10) == -1){      printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);      exit(0);      }      printf("======waiting for client's request======\n");      while(1){  //阻塞直到有用戶端串連,不然多浪費CPU資源。          if( (connect_fd = accept(socket_fd, (struct sockaddr*)NULL, NULL)) == -1){          printf("accept socket error: %s(errno: %d)",strerror(errno),errno);          continue;      }  //接受用戶端傳過來的資料      n = recv(connect_fd, buff, MAXLINE, 0);  //向用戶端發送回應資料      if(!fork()){ /*紫禁城*/          if(send(connect_fd, "Hello,you are connected!\n", 26,0) == -1)          perror("send error");          close(connect_fd);          exit(0);      }      buff[n] = '\0';      printf("recv msg from client: %s\n", buff);      close(connect_fd);      }      close(socket_fd);  }  

Makefile檔案為:

tcp_server:tcp_server.c#arm-cortex_a9-linux-gnueabi-gcc -o tcp_server tcp_server.cgcc -o tcp_server tcp_server.c

如果想在arm的開發板上運行該伺服器,那麼使用注釋掉的指令,在PC中運行使用gcc編譯。

關於Linux的socket,可以參考這裡http://blog.csdn.net/hguisu/article/details/7445768。


源碼:http://download.csdn.net/detail/u010406724/8558445

歡迎轉載,轉載請註明原地址:http://blog.csdn.net/wang_shuai_ww/article/details/44835075

Android socket 學習記錄 之 執行new socket(ip, port)程式崩潰

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.