關於網絡通信:每一臺電腦都有自己的ip地址,每臺電腦上的網絡應用程序都有自己的通信端口,張三的電腦(ip:192.168.1.110)上有一個網絡應用程序A(通信端口5000),李四的電腦(ip:192.168.1.220)上有一個網絡應用程序B(通信端口8000),張三給李四發消息,首先你要知道李四的ip地址,向指定的ip(李四ip:192.168.1.220)發信息,信息就發到了李四的電腦。再指定一下發送的端口號(通信端口8000),信息就發到了李四電腦的網絡應用程序B上。
TCP--一種網絡通信方式而已。分爲服務器(網絡應用程序)和客戶端(網絡應用程序),TCP通信過程,首先打開服務器,監聽自己的網絡通信端口(假設爲9000),打開客戶端,設置好要連接的ip地址和服務器的網絡通信端口(9000),這樣服務器一旦監聽到網絡通信端口有連接,二者就建立了連接。
好一步一步寫程序(最後有源碼!!!!!!!)
怎樣建立工程就不說了
在佈局文件里加入兩個按鈕(button),一個控制連接,一個控制發送消息;四個輸入文本框(edittext),一個填寫發送的信息內容,一個顯示服務器發來的消息。一個填寫要鏈接的ip地址,一個填寫要鏈接的端口號
佈局代碼
<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.wifi123.MainActivity" >以上都不用管的,軟件自動生成的,配置界面的
<!--顯示的標題:目標IP地址-->
<TextView
android:textSize="20dp"字體大小
android:id="@+id/IP_tv" id號
android:text="目標IP地址" 顯示的內容
android:layout_width="wrap_content" 寬度隨內容而定
android:layout_height="wrap_content" 高度度隨內容而定
/>
<!--顯示的標題:目標端口號-->
<TextView
android:textSize="20dp"
android:id="@+id/Port_tv"
android:text="目標端口號"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/IP_tv" 在<!--顯示的標題:目標IP地址-->的下面
android:layout_marginTop="30dp" 離它上面那個組件(<!--顯示的標題:目標IP地址-->)的距離
/>
<!-- 用於填寫ip地址的文本框-->
<EditText
android:text="192.168.4.1"
android:id="@+id/ip_ET"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/IP_tv" 在<!--顯示的標題:目標IP地址-->的右面
/>
<!-- 用於填寫端口號的文本框-->
<EditText
android:text="8080"
android:id="@+id/Port_ET"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/Port_tv" 還是在誰誰誰的右面
android:layout_alignBottom="@id/Port_tv" 本元素的下邊緣和某元素的的下邊緣對齊
/>
<!-- 用於發送信息的文本框-->
<EditText
android:id="@+id/Send_ET"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/Port_tv" 在某元素的下方
/>
<!-- 用於連接的按鈕-->
<Button
android:text="連接"
android:id="@+id/Connect_Bt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="Connect_onClick"設置按鈕的動作監聽函數,其實有幾種寫法,就用最簡單的一種
android:layout_below="@id/Send_ET" 在某元素的下方
/>
<!-- 用於發送信息的按鈕-->
<Button
android:text="發送"
android:id="@+id/Send_Bt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="Send_onClick"
android:layout_below="@id/Send_ET"
android:layout_alignParentRight="true" 貼緊父元素的右邊緣,指的是整體的界面
/>
<!-- 用於接收信息的文本框-->
<EditText
android:background="@android:color/darker_gray"
android:id="@+id/Receive_ET"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/Connect_Bt"
android:layout_alignParentBottom="true" 貼緊父元素的下邊緣
/>
</RelativeLayout>
看看佈局界面
接着開始編寫功能程序
先做點擊連接按鈕就連接服務器
查看java的API文檔,裏面封裝了專門用於TCP客戶端通信的類,和方法
裏面有一個類Socket (客服端),有一個它的構造方法
Socket(InetAddress address, int port)
創建一個流套接字並將其連接到指定 IP 地址的指定端口號。
意思是Socket socket = new Socket(InetAddress address, int port) ;//創建連接地址和端口,就去連接指定的ip和端口號去了,address填ip地址,port填端口號
只不過InetAddress是一個類,我們打開看一下
那麼
InetAddress ipAddress = InetAddress.getByName("192.168.4.1");
socket = new Socket(ipAddress, 8080);//創建連接地址和端口--------------就完了,客戶端就去連接了
但是ip地址和端口被我們定死了,,,,可不好玩,我們就設置成獲取ip文本框中的ip,端口號文本框中的端口號
InetAddress ipAddress = InetAddress.getByName(IPEditText.getText().toString());
int port =Integer.valueOf(PortText.getText().toString());//獲取端口號
socket = new Socket(ipAddress, port);//創建連接地址和端口-------------------這樣就好多了
但是由於在android幾開始,不允許在主線程裏連接服務器,所以只好讓按鈕點擊後啓動一個線程裏面寫上面的東西
package com.wifi123;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
Button ConnectButton;//定義連接按鈕
Button SendButton;//定義發送按鈕
EditText IPEditText;//定義ip輸入框
EditText PortText;//定義端口輸入框
EditText MsgText;//定義信息輸出框
EditText RrceiveText;//定義信息輸入框
Socket socket = null;//定義socket
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ConnectButton = (Button) findViewById(R.id.Connect_Bt);//獲得按鈕對象
SendButton = (Button) findViewById(R.id.Send_Bt);//獲得按鈕對象
IPEditText = (EditText) findViewById(R.id.ip_ET);//獲得ip文本框對象
PortText = (EditText) findViewById(R.id.Port_ET);//獲得端口文本框按鈕對象
}
public void Connect_onClick(View v) {
//啓動連接線程
Connect_Thread connect_Thread = new Connect_Thread();
connect_Thread.start();
}
class Connect_Thread extends Thread//繼承Thread
{
public void run()//重寫run方法
{
try
{
if (socket == null) //如果已經連接上了,就不再執行連接程序
{
//用InetAddress方法獲取ip地址
InetAddress ipAddress = InetAddress.getByName(IPEditText.getText().toString());
int port =Integer.valueOf(PortText.getText().toString());//獲取端口號
socket = new Socket(ipAddress, port);//創建連接地址和端口-------------------這樣就好多了
}
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
對了需要添加兩個權限,一個是wifi權限,一個是internet
然後下載到手機因爲我的電腦的ip爲192.168.1.101,所以我把192.168.4.1改了,192.168.4.1是爲了做與wifi模塊EPS8266通信使得
然後打開網絡調試助手,點擊連接(可以關閉電腦防火牆),然後點擊手機上的連接
好接着,連接按鈕按一下連接,再按一下斷開連接,並且,連接後按鈕上顯示斷開,斷開後按鈕上顯示連接
按鈕事件改爲
public void Connect_onClick(View v) {
if (isConnect == true) //標誌位 = true表示連接
{
isConnect = false;//置爲false
ConnectButton.setText("斷開");//按鈕上顯示--斷開
//啓動連接線程
Connect_Thread connect_Thread = new Connect_Thread();
connect_Thread.start();
}
else //標誌位 = false表示退出連接
{
isConnect = true;//置爲true
ConnectButton.setText("連接");//按鈕上顯示連接
try
{
socket.close();//關閉連接
socket=null;
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
你可以試一試了
接着寫點擊發送按鈕把發送信息文本框的內容發送出去
先貼代碼
public void Send_onClick(View v) {
try
{
//獲取輸出流
outputStream = socket.getOutputStream();
//發送數據
outputStream.write(MsgEditText.getText().toString().getBytes());
//outputStream.write("0".getBytes());
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
看看javaAPI
所以纔有了
//獲取輸出流
OutputStream outputStream = socket.getOutputStream();
//發送數據
outputStream.write(MsgEditText.getText().toString().getBytes());
接收數據並在信息框顯示出來
創建一個接收線程,在連接線程成功建立連接後啓動接收線程
//接收線程
class Receive_Thread extends Thread
{
public void run()//重寫run方法
{
try
{
while (true)
{
final byte[] buffer = new byte[1024];//創建接收緩衝區
inputStream = socket.getInputStream();
final int len = inputStream.read(buffer);//數據讀出來,並且返回數據的長度
runOnUiThread(new Runnable()//不允許其他線程直接操作組件,用提供的此方法可以
{
public void run()
{
// TODO Auto-generated method stub
RrceiveEditText.setText(new String(buffer,0,len));
}
});
}
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//連接線程
class Connect_Thread extends Thread//繼承Thread
{
public void run()//重寫run方法
{
try
{
if (socket == null)
{
//用InetAddress方法獲取ip地址
InetAddress ipAddress = InetAddress.getByName(IPEditText.getText().toString());
int port =Integer.valueOf(PortText.getText().toString());//獲取端口號
socket = new Socket(ipAddress, port);//創建連接地址和端口-------------------這樣就好多了
//在創建完連接後啓動接收線程
Receive_Thread receive_Thread = new Receive_Thread();
receive_Thread.start();
}
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
下面貼全部源碼
activity_mian.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.wifi123.MainActivity" >
<!--顯示的標題:目標IP地址-->
<TextView
android:textSize="20dp"
android:id="@+id/IP_tv"
android:text="目標IP地址"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<!--顯示的標題:目標端口號-->
<TextView
android:textSize="20dp"
android:id="@+id/Port_tv"
android:text="目標端口號"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/IP_tv"
android:layout_marginTop="30dp"
/>
<!-- 用於填寫ip地址的文本框-->
<EditText
android:text="192.168.1.101"
android:id="@+id/ip_ET"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/IP_tv"
/>
<!-- 用於填寫端口號的文本框-->
<EditText
android:text="8080"
android:id="@+id/Port_ET"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/Port_tv"
android:layout_alignBottom="@id/Port_tv"
/>
<!-- 用於發送信息的文本框-->
<EditText
android:id="@+id/Send_ET"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/Port_tv"
/>
<!-- 用於連接的按鈕-->
<Button
android:text="連接"
android:id="@+id/Connect_Bt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="Connect_onClick"
android:layout_below="@id/Send_ET"
/>
<!-- 用於發送信息的按鈕-->
<Button
android:text="發送"
android:id="@+id/Send_Bt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="Send_onClick"
android:layout_below="@id/Send_ET"
android:layout_alignParentRight="true"
/>
<!-- 用於接收信息的文本框-->
<EditText
android:background="@android:color/darker_gray"
android:id="@+id/Receive_ET"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/Connect_Bt"
android:layout_alignParentBottom="true"
/>
</RelativeLayout>
MainActivity.java源碼
package com.wifi123;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
boolean isConnect=true;//連接還是斷開
Button ConnectButton;//定義連接按鈕
Button SendButton;//定義發送按鈕
EditText IPEditText;//定義ip輸入框
EditText PortText;//定義端口輸入框
EditText MsgEditText;//定義信息輸出框
EditText RrceiveEditText;//定義信息輸入框
Socket socket = null;//定義socket
private OutputStream outputStream=null;//定義輸出流
private InputStream inputStream=null;//定義輸入流
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ConnectButton = (Button) findViewById(R.id.Connect_Bt);//獲得連接按鈕對象
SendButton = (Button) findViewById(R.id.Send_Bt);//獲得發送按鈕對象
IPEditText = (EditText) findViewById(R.id.ip_ET);//獲得ip文本框對象
PortText = (EditText) findViewById(R.id.Port_ET);//獲得端口文本框按鈕對象
MsgEditText = (EditText) findViewById(R.id.Send_ET);//獲得發送消息文本框對象
RrceiveEditText = (EditText) findViewById(R.id.Receive_ET);//獲得接收消息文本框對象
}
public void Connect_onClick(View v) {
if (isConnect == true) //標誌位 = true表示連接
{
isConnect = false;//置爲false
ConnectButton.setText("斷開");//按鈕上顯示--斷開
//啓動連接線程
Connect_Thread connect_Thread = new Connect_Thread();
connect_Thread.start();
}
else //標誌位 = false表示退出連接
{
isConnect = true;//置爲true
ConnectButton.setText("連接");//按鈕上顯示連接
try
{
socket.close();//關閉連接
socket=null;
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void Send_onClick(View v) {
try
{
//獲取輸出流
outputStream = socket.getOutputStream();
//發送數據
outputStream.write(MsgEditText.getText().toString().getBytes());
//outputStream.write("0".getBytes());
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//連接線程
class Connect_Thread extends Thread//繼承Thread
{
public void run()//重寫run方法
{
try
{
if (socket == null)
{
//用InetAddress方法獲取ip地址
InetAddress ipAddress = InetAddress.getByName(IPEditText.getText().toString());
int port =Integer.valueOf(PortText.getText().toString());//獲取端口號
socket = new Socket(ipAddress, port);//創建連接地址和端口-------------------這樣就好多了
//在創建完連接後啓動接收線程
Receive_Thread receive_Thread = new Receive_Thread();
receive_Thread.start();
}
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//接收線程
class Receive_Thread extends Thread
{
public void run()//重寫run方法
{
try
{
while (true)
{
final byte[] buffer = new byte[1024];//創建接收緩衝區
inputStream = socket.getInputStream();
final int len = inputStream.read(buffer);//數據讀出來,並且返回數據的長度
runOnUiThread(new Runnable()//不允許其他線程直接操作組件,用提供的此方法可以
{
public void run()
{
// TODO Auto-generated method stub
RrceiveEditText.setText(new String(buffer,0,len));
}
});
}
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}