Android 网络通信之——Socket

Socket,又称“套接字”,是网络上运行的两个程序间双向通讯的一端,它既可以接受请求,也可以发送请求,利用它可以较为方便的编写网络上的数据的传递。在java中,有专门的socket类来处理用户的请求和响应。利用SOCKET类的方法,就可以实现两台计算机之间的通讯。Java中能够接受其他通信实体连接请求的类是ServerSocket类,该对象用于监听来自客户端Socket的连接。如果没有连接,它将一直处于等待的状态。

TCP的使用

TCP协议被称着一种端对端的协议,这是因为它为两台计算机之间的连接起了重要作用。当一台计算机需要与另外一台远程计算机连接时,TCP协议会让它们建立一个链接,用于发送和接收数据的虚拟链接。

客户端(client): 发送数据和接收数据 ——>Socket
服务端(server): 负责去分发以处理相关数据 ——>ServerSocket

如何建立一个服务端

1
2
3
4
5
6
7
8
9
//创建一个ServerSocket,用于监听客户端Socket的连接请求
ServerSocket serverSocket = new ServerSocket(8080);
//采用循环不断的接受来自客户端的请求
while(true){
//每当接受的客户端Socket的请求,服务端也对应产生一个
Socket socket = serverSocket.accept();
//下面就可以进行Socket通信了
.........
}

如何建立一个客户端

1
2
3
4
//创建连接到本机、8080端口的Socket
Socket socket = new Socket("192.168.1.1", 8080);
//下面就可以进行Socket通信了
.........

简单通信示例

一个简单的示例,客户端界面上一个文本编辑框、一个按钮和一个文本显示。客户端输入内容在文本编辑框,然后点击按钮发送到服务器,服务器然后再返回给客户端,显示到文本显示控件上,完成客户端与服务器的通信。

服务器

SocketServer.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public class SocketServer implements Runnable {

//创建一个ServerSocket对象
private ServerSocket serverSocket;
//创建一个Socket对象
private Socket client;

public void run() {
try {
//实例化ServerSocket对象,设置服务端端口8080
serverSocket = new ServerSocket(8080);
System.out.println("服务器已启动,等待客户端连接...");
while (true) {
//不断循环,接受客户端的访问
client = serverSocket.accept();
System.out.println("客户端已连接");
System.out.println("============");
try {
// 接收客户端信息
BufferedReader in = new BufferedReader(
new InputStreamReader(client.getInputStream()));
String str = in.readLine();
System.out.println("客户端:" + str);

// 向客户端发送信息
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(client.getOutputStream())),
true);
System.out.println("服务器发送:" + str);
out.println("服务器:" + str);

//本次会话完成,关闭输入输入出流
in.close();
out.close();
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
} finally {
//关闭输入Socket对象
client.close();
System.out.println("============");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
* @param args
*/
public static void main(String[] args) {
//创建线程
Thread thread = new Thread(new SocketServer());
//开启线程
thread.start();
}
}

客户端

XML文件

activity_main.xml

socket_basic_xml

Java 代码

MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package com.example.shoewann.socketclient;

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private static final String TAG = "MainActivity";
private android.widget.EditText editText;
private android.widget.Button button;
private android.widget.TextView textView;
private static final String IP_ADDRESS = "192.168.1.189";
private static final int IP_PORT = 8080;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

initView();
initData();
}

private void initData() {
this.button.setOnClickListener(this);
}

private void initView() {
this.textView = (TextView) findViewById(R.id.textView);
this.button = (Button) findViewById(R.id.button);
this.editText = (EditText) findViewById(R.id.editText);
}

@Override
public void onClick(View v) {
switch (v.getId()) {

case R.id.button:
final String message = editText.getText().toString();
editText.getText().clear();
new Thread(new Runnable() {
@Override
public void run() {

try {
Socket socket = new Socket(IP_ADDRESS, IP_PORT);
//客户端=>向服务器=>发送信息
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())),
true);
Log.e(TAG, "Socket send Message:==>" + message);
out.println(message);

//客户端=>接收=>服务器=>返回信息
BufferedReader br = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String msg = br.readLine();
Log.e(TAG, "Socket receiver Message:==>" + message);
//实例化Handler类和Message发送消息给主线程更新UI
MyHandler handler = new MyHandler(getMainLooper());
Message mMessage = handler.obtainMessage();
mMessage.what = 0x123;
mMessage.obj = msg;
handler.sendMessage(mMessage);
//注意最后要关闭输入输出流
out.close();
br.close();
//关闭socket对象
socket.close();
} catch (Exception e) {
e.printStackTrace();
Log.w(TAG, e.toString());
}
}
}).start();
break;
default:
break;
}
}

class MyHandler extends Handler {
public MyHandler(Looper looper) {
super(looper);
}

@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0x123:
//获得消息中服务器返回的数据,显示到UI上
if (msg.obj != null) {
textView.setText(msg.obj.toString());
} else {
textView.setText("服务器返回数据错误");
}
break;
default:
break;
}
}
}
}

效果图

客户端发送前:

socket_basic_client_send

服务端收到信息并返回:

socket_basic_server

客户端收到服务器返回的信息:

socket_basic_client_receiver

简易聊天室示例

以下的示例简单的实现你一个简易的聊天室效果

服务器

SocketThread.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class SocketThread implements Runnable {

//定义处理当前线程的Socket
Socket socket=null;
//该线程处理Socket所对应的输入流
BufferedReader bf=null;

public SocketThread(Socket s){
this.socket=s;
try {
//初始化该socket对应的输入流
bf=new BufferedReader(new InputStreamReader(s.getInputStream(),"utf-8"));
}catch(UnsupportedEncodingException e){
e.printStackTrace();
System.out.println("SocketThread UnsupportedEncodingException :===>"+e.getMessage());
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println("SocketThread Exception :====>"+e.getMessage());
}
}
public void run() {
// TODO Auto-generated method stub
try {
String content=null;
while ((content=readMessageFromeClient())!=null) {
//遍历socketList中的每一个socket对象,将读取到的内容向每个socket发送一次
for (Socket socket : AndroidThreadServer.socketList) {
//创建输出流对象
OutputStream outputStream;
outputStream=socket.getOutputStream();
System.out.println(content+"\n");
outputStream.write((content+"\n").getBytes("utf-8"));
}
}
} catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
System.out.println("Run IOException :===>"+e.getMessage());
}
}
private String readMessageFromeClient(){

try {
return bf.readLine();
} catch (IOException e) {
//如果发生了异常,表示客户端已近关闭,应该删掉socket
AndroidThreadServer.socketList.remove(socket);
e.printStackTrace();
System.out.println("readMessageFromeClient IOException :===>"+e.getMessage());
}
return null;
}

}

AndroidThreadServer.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class AndroidThreadServer {

//定义保存所有socket的list对象
public static List<Socket> socketList=new ArrayList<Socket>();

public static void main(String[] args) {
try {
//创建socket对象,使用端口8080
ServerSocket serverSocket=new ServerSocket(8080);
//不断的循环,接受客户端的访问
while (true) {
//创建Socket对象,使用accept()方法不断的创建
Socket socket=serverSocket.accept();
//将socket对象添加到list集合里
socketList.add(socket);
//客户端连接成功后启启动一条SocketThread线程为该客户的服务
new Thread(new SocketThread(socket)).start();
}

} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println("AndroidThreadServer Exception:===>"+e.getMessage());
}
}
}

客户端

XML 布局

activity_main.xml

socket_chat_xml

Java 代码

ClientThread.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class ClientThread implements Runnable {


private static final String TAG = "ClientThread";

//声明Socket对象
private Socket mSocket = null;

//声明Handler对象
private Handler mHandler = null;

//声明BufferedReader对象
private BufferedReader bf = null;


public ClientThread(Socket socket, Handler handler) {
this.mSocket = socket;
this.mHandler = handler;
try{
//获取BufferedReader 对象
bf=new BufferedReader(new InputStreamReader(socket.getInputStream()));
}catch (IOException e){
e.printStackTrace();
Log.w(TAG, "ClientThread IOException: ====>"+e.getMessage());
}
}

@Override
public void run() {
String content=null;
try {
//循环读取内容
while ((content=bf.readLine())!=null){
//构建消息对象
Message msg=mHandler.obtainMessage();
//设置消息对象模式与内容
msg.what=0x123;
msg.obj=content;
mHandler.sendMessage(msg);

}
}catch (IOException e){
e.printStackTrace();
Log.w(TAG, "Run IOException: ====>"+e.getMessage());
}
}
}

MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private static final String TAG = "MainActivity";
public android.widget.TextView tvshow;
private android.widget.EditText edinput;
private android.widget.Button btnsend;
private static final String IP_ADDRESS = "192.168.1.189";
private static final int IP_PORT = 8080;
private OutputStream output = null;
private Socket mSocket = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

initView();
iniData();
}

private void initView() {
this.btnsend = (Button) findViewById(R.id.btn_send);
this.edinput = (EditText) findViewById(R.id.ed_input);
this.tvshow = (TextView) findViewById(R.id.tv_show);

}

private void iniData() {
this.btnsend.setOnClickListener(this);
SocketHandler handler = new SocketHandler(Looper.getMainLooper());
initSocket(handler);
}

public void initSocket(final Handler handler) {

new Thread(new Runnable() {
@Override
public void run() {
try {
mSocket = new Socket(IP_ADDRESS, IP_PORT);
//启动子线程,每一个线程处理对应的socket
new Thread(new ClientThread(mSocket, handler)).start();
//实例化输出流对象
output = mSocket.getOutputStream();

} catch (UnknownHostException e) {
e.printStackTrace();
Log.w(TAG, "initSocket tUnknownHostException : ==> " + e.getMessage());
} catch (IOException e) {
e.printStackTrace();
Log.w(TAG, "initSocket IOException : ==> " + e.getMessage());
}
}
}).start();
}

class SocketHandler extends Handler {

public SocketHandler(Looper looper) {

super(looper);
}

@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//判断是否有子线程传递过来的消息
switch (msg.what) {

case 0x123:
//将服务器的消息追加到textview控件上进行显示
MainActivity.this.tvshow.append(msg.obj.toString()+"\n");
break;
}
}
}

@Override
public void onClick(View v) {

switch (v.getId()) {
case R.id.btn_send:
try {
Date date=new Date();
DateFormat format=new SimpleDateFormat("HH:mm:ss");
String time=format.format(date);
//将文本输入框的文本信息写入流
output.write((getlocalip()+"\t\t["+time+"]\n"+edinput.getText().toString() + "\n").getBytes());
//将文本输入框内容置空
edinput.getText().clear();
//edinput.setText("");

} catch (UnknownHostException e) {
e.printStackTrace();
Log.w(TAG, "onClick UnknownHostException : ==> " + e.getMessage());
} catch (IOException e) {
e.printStackTrace();
Log.w(TAG, "onClick IOException : ==> " + e.getMessage());
}
break;
}

}
private String getlocalip(){
WifiManager wifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
int ipAddress = wifiInfo.getIpAddress();
Log.d(TAG, "int ip "+ipAddress);
if(ipAddress==0)return null;
return ((ipAddress & 0xff)+"."+(ipAddress>>8 & 0xff)+"."
+(ipAddress>>16 & 0xff)+"."+(ipAddress>>24 & 0xff));
}
}

效果图

客户端 A:

socket_chat_client_one

客户端 B:

socket_chat_client_two

服务端:

socket_chat_server

以上简单的介绍了Socket网络通信相关内容,如果不足,欢迎指正。

0%