Socket 网络通信
1.OSI (Open System Interconnect Reference Model)(开放系统互联参考模型)
从下低到高 :物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。
2.TCP/IP
TCP/IP 是一个协议族,里边包括很多协议,TCP,IP知识两个很重要的协议。
TCP(Transmission Control Protocol,传输控制协议) 是面向连接的协议,在收发数据时,都需要与对面建立连接,TCP协议能够确保数据在传输过程中不会遗失。它的缺点是过程复杂,消耗的资源更多。
UDP(User Datagram Protocol)用户数据报协议,相比TCP就是无需建立连接,结构简单,无法保证正确性,容易丢包。
3.Socket 实现网络通信
Socket(套接字),用来描述IP地址和端口,是通信链的句柄,应用程序可以通过Socket向网络发送请求或者应答网络请求。Socket是支持TCP/IP协议的网络通信的基本操作单元。
3.1 实现服务端和客户端连接
服务端:
// 1.创建服务端 Socket 并绑定端口
ServerSocket serverSocket=new ServerSocket(6666);
String ip=InetAddress.getLocalHost().getHostAddress();
S.println("~ ~ ~ 服务端已开启。 IP:"+ip);
// 2.调用 accept() 方法,等待客户连接
Socket socket=serverSocket.accept();
// 3.获取输入流
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
//4. 不断读取客户端信息
String info;
while ((info=bufferedReader.readLine())!=null){
S.println(info);
}
socket.shutdownInput(); //关闭输入流
socket.close();//关闭连接
客户端:
private void acceptServer() throws IOException {
// 1.创建客户端Socket,指定服务器地址和端口
Socket socket=new Socket(IP,PORT);
// 2.获取输出流
OutputStream outputStream=socket.getOutputStream();
String string = "Tiger connect to server.";
// 3.向输出流中写入数据
outputStream.write(string.getBytes());
outputStream.flush(); // *** 强制发送缓冲区数据 ***
socket.shutdownOutput(); //关闭输出流
socket.close();//关闭连接
}
3.2 多个客户端之间通信
实际上是所有客户端都向服务端发送消息,然后服务端再将消息返回给所有客户端。
服务端:
public class Server {
private static final int PORT = 6666; //端口
private List<Socket> list = new ArrayList<>(); //存储所有客户端
private ServerSocket serverSocket = null;
private ExecutorService myExecutorService = null; //线程池
public static void main(String[] args) throws IOException {
new Server(); //在构造函数中开启服务端
}
public Server() throws IOException {
// 1.创建Socket 服务并指定端口
serverSocket = new ServerSocket(PORT);
// 2.创建线程池
myExecutorService = Executors.newCachedThreadPool();
S.println("Server is running...");
// 3.不断地等待客户端连接,当有客户端连接后,添加到Socket集合,开启新的线程到线程池中
Socket client = null;
while (true) {
client = serverSocket.accept();
list.add(client);
myExecutorService.execute(new Service(client));
}
}
class Service implements Runnable {
private Socket socket;
private BufferedReader br;
private String msg;
public Service(Socket socket) throws IOException {
this.socket = socket;
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
msg = "User:" + socket.getInetAddress().getHostAddress() + " ~ join the chat group. The amount of online:" + list.size();
this.sendMessage();
}
@Override
public void run() {
try {
// 不断接受客户端发来的消息,直到客户端退出, “bye”
while (true) {
if ((msg = br.readLine()) != null) {
if (msg.equals("bye")) { //客户端退出
S.println(" ~~~ ~~~ ~~~ ~~~ ");
list.remove(socket);
socket.close();
msg = "User:" + socket.getInetAddress() + " exit. The amount of online:" + list.size();
this.sendMessage();
break; // *** 退出循环 ***
} else { //客户端发送消息
msg = socket.getInetAddress() + " say:" + msg;
this.sendMessage();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
//为连接上服务端的每个客户端发送消息
public void sendMessage() throws IOException {
S.println(msg);
//向每个客户端发送消息
for (Socket socketClient : list) {
try {
PrintWriter pout = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socketClient.getOutputStream(),"UTF-8")),true);
pout.println(msg);
}catch (IOException e) {e.printStackTrace();}
}
}
}
}
客户端:
public class MainActivity extends AppCompatActivity implements Runnable {
private final String IP = "10.0.2.2"; //IP
private final int PORT = 6666; //端口
private EditText etMessage;
private TextView tvMessage;
private Socket socket;
private BufferedReader br;
private OutputStream outputStream;
private String msg;
private PrintWriter pw;
private boolean bIsClosed = false; //是否退出
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Init controls
etMessage = (EditText) findViewById(R.id.et_Message);
tvMessage = (TextView) findViewById(R.id.tv_Message);
connectToServer();
new Thread(MainActivity.this).start();
}
//连接到服务端
private void connectToServer() {
new Thread(new Runnable() {
@Override
public void run() {
try {
// 1.创建客户端Socket,指定服务器地址和端口
socket = new Socket(IP, PORT);
// 2.获取输入流
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 3.获取输出流
outputStream = socket.getOutputStream();
pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)), true);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
public void onClick(View view) throws IOException {
//Send message
msg = etMessage.getText().toString();
sendMessage();
}
public void sendMessage(){
//Socket 已经连接,并且输出流没有关闭
if (socket.isConnected() && !socket.isOutputShutdown()) {
new Thread(new Runnable() {
@Override
public void run() {
if (bIsClosed)
pw.println("bye");
else
pw.println(msg);
}
}).start();
}
}
@Override
public void run() {
try {
//不断地从输入流中读取数据
while (true) {
//Socket已经连接
if (socket != null) {
if ((msg = br.readLine()) != null) {
runOnUiThread(new Runnable() {
@Override
public void run() {
tvMessage.setText(tvMessage.getText().toString() + msg + "
");
}
});
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
bIsClosed = true;
sendMessage();
super.onDestroy();
}
}
3.3 Socket 上传文件
服务端:
// 1.创建服务端 Socket 并绑定端口
ServerSocket serverSocket=new ServerSocket(8888);
S.println("~~~ Server is running,waiting for client ~~~");
// 2.调用 accept() 方法,等待客户连接
Socket socket=serverSocket.accept();
// 3.获取输入流
InputStream inputStream = socket.getInputStream();
// 4.获取文件名称
String fileName="";
int len2;
while ((len2=inputStream.read())!=-1){
if(len2==' ')
break;
else
fileName+=String.valueOf ((char)(len2));
}
// 5.创建文件,用来存储用户上传数据
FileOutputStream outputStream=new FileOutputStream(fileName,true);
// 6.将用户上传文件保存到本地
int len;
byte[] buffer=new byte[1024];
while ((len=inputStream.read(buffer,0,buffer.length))!=-1){
outputStream.write(buffer,0,len);
}
outputStream.close();
inputStream.close();
socket.shutdownInput(); //关闭输入流
socket.close();//关闭连接
客户端:
new AsyncTask<Void, Integer, Void>() {
@Override
protected Void doInBackground(Void... params) {
try {
//1.创建Socket对象并获取输出流
Socket socket = new Socket(IP, PORT);
OutputStream outputStream = socket.getOutputStream();
// 2.写入文件名称,最后使用 分割
outputStream.write("Video5.mp4 ".getBytes());
// 3.读取文件内容
InputStream inputStream=getResources().openRawResource(R.raw.video);
// 4.上传文件
int len;
byte[] buffer = new byte[1024];
while ((len = inputStream.read(buffer, 0, buffer.length)) != -1) {
outputStream.write(buffer, 0, len);
outputStream.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
Toast.makeText(UDPActivity.this, "Upload successfully.", Toast.LENGTH_SHORT).show();
}
}.execute();
3.4UPD 通信
服务端:
//1.创建服务端 DatagramSocket 指定端口
DatagramSocket socket=new DatagramSocket(8888);
//2.创建数据报,用于接受客户端发送的数据
byte[] data=new byte[1024]; //指定接受数据包的大小
DatagramPacket packet=new DatagramPacket(data,data.length);
//3.接受客户端发送的数据
S.println("~~~ Server is running,waiting for client ~~~");
while (true){
socket.receive(packet);
//4.读取数据
String info=new String(data,0,data.length);
S.println("Client:"+ info);
if(socket.isClosed())
{
S.println("Client has been exit.");
break;
}
}
socket.close(); //关闭 Socket
客户端:
new Thread(new Runnable() {
@Override
public void run() {
try {
//1.获取 InetAddress 对象,指定IP
InetAddress address = InetAddress.getByName(IP);
//2.要发送的信息
byte[] data = "Test".getBytes();
//3.创建 DatagramSocket,用来发送数据
DatagramSocket socket = new DatagramSocket();
//4.创建 DatagramPacket,用来存储要发送的数据,并指定目标IP和端口
DatagramPacket packet = new DatagramPacket(data, data.length, address, PORT);
//5.发送消息到服务端
socket.send(packet);
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
3.5UPD 发送文件
服务端:
//1.创建服务端 DatagramSocket 指定端口
DatagramSocket socket=new DatagramSocket(8888);
S.println("~~~ Server is running,waiting for client ~~~");
//2.创建文件,用来存储用户上传数据
File file=new File("Video.mp4");
FileOutputStream outputStream=new FileOutputStream("Video.mp4",true);
//3.不断接受客户端发送的数据
while (true){
//4.创建数据报,用于接受客户端发送的数据
byte[] buffer=new byte[1024]; //指定接受数据包的大小
DatagramPacket packet=new DatagramPacket(buffer,buffer.length);
socket.receive(packet);
//5.将数据写入文件
outputStream.write(buffer,0,packet.getLength());
if(socket.isClosed())
break;
}
outputStream.close();
socket.close(); //关闭 Socket
客户端:
new AsyncTask<Void, Integer, Void>() {
@Override
protected Void doInBackground(Void... params) {
try {
//1.创建Socket对象并获取输出流
Socket socket = new Socket(IP, PORT);
OutputStream outputStream = socket.getOutputStream();
// 2.写入文件名称,最后使用 分割
outputStream.write("Video5.mp4 ".getBytes());
// 3.读取文件内容
InputStream inputStream=getResources().openRawResource(R.raw.video);
// 4.上传文件
int len;
byte[] buffer = new byte[1024];
while ((len = inputStream.read(buffer, 0, buffer.length)) != -1) {
outputStream.write(buffer, 0, len);
outputStream.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
Toast.makeText(UDPActivity.this, "Upload successfully.", Toast.LENGTH_SHORT).show();
}
}.execute();
学习自:http://www.runoob.com/w3cnote/android-tutorial-socket-intro.html