TCP/IP是什么?
TCP/IP(Transmission Control Protocol/Internet Protocol)是一种用于电子设备之间通过网络进行通信的标准,定义了电子设备(如计算机,路由器等)如何发送数据到另一个设备。这个协议集包括两个主要部分,传输控制协议(TCP)和网际协议(IP):
-
启动控制协议(TCP): TCP主要负责在数据从源到目的地移动时的数据整合和错误检查。它将大块数据分解成更小的数据包,然后在接收方组装这些小的数据包成完整的消息包。
-
网际协议(IP): IP负责数据包的发送和寻址。每一个在线的设备都至少拥有一个公共IP地址,这个地址唯一地标识了强联网上的每一个设备。IP用这些地址把数据正确送达目的
实际上就是将TCP协议与IP协议综合使用
协议分层
在应用编写上我们只需了解应用层。
套接字方法
在应用层套接字方法(Socket methods)是网络编程中的一种用来创建并管理网络连接的工具。更具体的说,套接字提供一个编程接口(API),用于建立网络连接并进行数据发送和接收。这些方法通常来自socket
这个库,它在Python,Java,C++等多种编程语言中都存在。下面是一些常见的套接字方法:
socket()
: 创建一个新的套接字对象。bind()
: 绑定套接字到一个地址和端口。listen()
: 开始监听来自客户端的连接。accept()
: 接受一个客户端连接,并返回一个新的套接字和客户端的地址。connect()
: 连接到远程服务器。send()
: 发送数据到连接的套接字。recv()
: 接收来自套接字的数据。close()
: 关闭套接字连接。
使用这些方法,程序员可以创建服务器和客户端,在这两者之间建立连接,然后发送和接收数据。
代码部分
AndroidManifest.xml
首先我们需要对AndroidManifest.xml进行修改
<uses-permission android:name="android.permission.INTERNET"/><!--获取Internet权限-->
将上述代码插入至<manifest>首标签后。
TCPServer.java Service类
然后新建一个Service,可以命名为TCPServer
public class TCPService extends Service {
private Intent intent;
private ServerSocket serverSocket;
private Socket socket;
private BufferedReader reader;
private PrintWriter writer;
private boolean isRunning=false;
private Thread tcpThread;
private static final int port=9999;//端口定义
@Override
public void onCreate(){
super.onCreate();
}
@Override
public int onStartCommand(Intent intent,int flags,int startID){
if(!isRunning&&"TCP_SERVICE_START".equals(intent.getAction())){
isRunning=true;
startServer();
}//收到开启服务的意图
else if(isRunning&&"TCP_MESSAGE_SEND".equals(intent.getAction())){
String message=intent.getStringExtra("messageSe");
sendMessageToClient(message);
}//收到发送信息的意图
return super.onStartCommand(intent, flags, startID);
}
@Override
public void onDestroy(){
super.onDestroy();
if(isRunning){
isRunning=false;
try{
serverSocket.close();
}catch (IOException e){
e.printStackTrace();
}
tcpThread.interrupt();
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void startServer() {
tcpThread=new Thread(() -> {
try{
serverSocket=new ServerSocket(port);//创建一个新的套接字对象
while(isRunning){
socket=serverSocket.accept();//接受一个客户端连接,并返回一个新的套接字和客户端的地址
reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));//读取器
writer=new PrintWriter(socket.getOutputStream(),true);//发送器
String message=reader.readLine();
intent=new Intent("TCP_MESSAGE_RECEIVED");
intent.putExtra("messageRe",message);
LocalBroadcastManager.getInstance(TCPService.this).sendBroadcast(intent);//通过广播可以让其它类获取收到的内容
}
}catch (IOException e){
e.printStackTrace();
}
});
tcpThread.start();
}
private void sendMessageToClient(String message){
Thread sendThread = new Thread(() -> writer.println(message));
sendThread.start();
sendThread.interrupt();
}
}
注意:在接收和发送时,应在新的线程中进行,以防进程冲突
用到的库
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
activity_main.xml和string.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".MainActivity">
<android.widget.LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.widget.TextView
android:id="@+id/text_filed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="100dp"
android:text="@string/textview_hint"
android:textSize="40sp" />
<android.widget.EditText
android:id="@+id/text_input"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="100dp"
android:autofillHints="Hello!"
android:inputType="text"
android:text="@string/edittext_hint"
android:textSize="40sp"
tools:ignore="LabelFor" />
<android.widget.Button
android:id="@+id/button_send"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="100sp"
android:text="@string/button_send"
android:textSize="50sp"/>
</android.widget.LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<resources>
<string name="app_name">TCPServer</string>
<string name="textview_hint">等待接收</string>
<string name="edittext_hint">输入要发送的内容</string>
<string name="button_send">发送</string>
<string name="button_status">STATUS</string>
</resources>
可以根据个人需求调整
MainActivity.java
public class MainActivity extends AppCompatActivity {
private BroadcastReceiver receiver;
private String messageRe,messageSe;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent startService = new Intent(this, TCPService.class);
startService.setAction("TCP_SERVICE_START");
startService(startService);//启动服务
TextView textView=findViewById(R.id.text_filed);
EditText editText=findViewById(R.id.text_input);
Button button = findViewById(R.id.button_send);
receiver=new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
messageRe="Received:"+intent.getStringExtra("messageRe");
textView.setText(messageRe);
}
};
IntentFilter filter = new IntentFilter("TCP_MESSAGE_RECEIVED");
LocalBroadcastManager.getInstance(this).registerReceiver(receiver, filter);
//广播接收器
button.setOnClickListener(view -> {
messageSe=editText.getText().toString();
Intent sendMessage=new Intent(this,TCPService.class);
sendMessage.putExtra("messageSe",messageSe);
sendMessage.setAction("TCP_MESSAGE_SEND");
startService(sendMessage);
});//按钮点击监听器
}
@Override
protected void onDestroy(){
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
}
}
用到的库
import androidx.appcompat.app.AppCompatActivity;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
到此完成了所有代码部分,接下来可以测试了,注意设备的IP地址、子网掩码、网关和首选DNS设置,以及IPV4和IPV6的选择,并且注意程序在端口设置中一般取8000以上。