创建服务器端的步骤:
1,指定端口实例化一个ServerSocket
2,调用ServerSocket的accept方法等待连接期间阻塞
3,获取位于底层的Socket流进行读写操作
4,将数据封装成流
5,对Socket进行读写
6,关闭流
创建客户端的步骤:
1,通过IP地址和端口实例化Socket,请求连接服务器
2,获取位于底层的Socket流进行读写操作
3,将数据封装成流(BufferedReader/PrintWriter,DataOutputStream/DataInputStream)的实例
4,对Socket进行读写
5,关闭流
使用ServerSocket创建服务器端:
public static void main(String[] args) throws IOException { // TODO Auto-generated method stub //创建一个ServerSo查看特,用于监听客户端Socket的连接请求 ServerSocket ss=new ServerSocket(3000); while(true){ //每当接收到客户端Socket的请求,服务器端也对应产生一个Socket,没接收到请求就等待。。 Socket s=ss.accept(); OutputStream os=s.getOutputStream();//服务器端产生的Socket获取输出流 os.write("您好,您收到了来自服务器的祝福!\n".getBytes()); os.close(); s.close(); } }客户端使用Socket通信:
package com.example.simpleclient; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; 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.widget.TextView; public class MainActivity extends Activity { TextView text; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); text=(TextView) findViewById(R.id.text); new Thread(){ @Override public void run() { // TODO Auto-generated method stub try { //建立连接到远程服务器的的Socket,Ip是服务器端PC的IP,测试环境是PC端服务器,手机当客户端,PC和手机要连接同一个局域网,PC和手机在同一网段 Socket socket = new Socket("192.168.88",3000); //将Socket对应的输入流包装秤BufferedReader BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream())); String line=br.readLine(); text.setText("来自服务的数据:"+line); br.close(); socket.close(); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }.start(); } }
<!-- 访问网络权限 --> <uses-permission android:name="android.permission.INTERNET"/>
在客户端:
socket.getInputStream();从socket读来自服务器的数据
socket.getOutputStream();向socket中写数据,传给服务器,服务器在它的socket的输入流读这个数据
在服务器端:
socket.getInputStream();从socket读来自客户端的数据
socket.getOutputStream();向socket中写数据,传给客户端,客户端在它的socket的输入流读这个数据
就是说客户端和服务器端的输入输出流是对应的,输入流连接到输出流
输入输出流的包装:
第一种方法:数据二进制流
DataInputStream in=new DataInputStream(socket.getInputStream());//接收客户端信息 DataOutputStream out=new DataOutputStream(socket.getOutputStream()); //向客户端发送消息第二种方法:
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
socketClient,java
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.Socket; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class socketClient extends Activity { private Button button; private TextView text; private EditText edit; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); button = (Button) findViewById(R.id.button); edit = (EditText) findViewById(R.id.edit); text = (TextView) findViewById(R.id.text); button.setOnClickListener(new View.OnClickListener() { private Socket socket = null; @Override public void onClick(View v) { // TODO Auto-generated method stub String sendMsg = edit.getText().toString() + "\r\n"; try { socket = new Socket("192.168.0.37", 8888); // 创建Socket,其中ip地址为我的PC机器的地址,手机通过wifi上网和服务器在一个网段 // PrintWriter out = new PrintWriter(new BufferedWriter(new // OutputStreamWriter(socket.getOutputStream())),true); // out.println(sendMsg); // // BufferedReader in = new BufferedReader(new // InputStreamReader(socket.getInputStream())); // String readMsg = in.readLine(); // if(readMsg !=null){ // text.setText(readMsg); // }else{ // text.setText("错误"); // } // // out.close(); // in.close(); // socket.close(); DataOutputStream out = new DataOutputStream(socket .getOutputStream()); // 向服务器发送消息 out.writeUTF(sendMsg); out.flush(); DataInputStream in = new DataInputStream(socket .getInputStream()); // 接收来自服务器的消息 String readMsg = in.readUTF(); if (readMsg != null) { text.setText(readMsg); } out.close(); in.close(); socket.close(); } catch (Exception e) { e.printStackTrace(); } } }); } }
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class Server { public Server(){ new ServerThread().start(); } class ServerThread extends Thread{ public void run() { try { ServerSocket ss=new ServerSocket(8888); ////创建一个ServerSocket对象,并让这个ServerSocket在8888端口监听 while(true){ Socket socket=ss.accept(); //调用ServerSocket的accept()方法,接受客户端所发送的请求,如果客户端没有发送数据,那么该线程就停滞不继续 // try { // BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); //接收客户端信息 // String readline = in.readLine(); // System.out.println("readline:"+readline); // // PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true); // out.println("link server success"); // // in.close(); //关闭流 // out.close();//关闭流 // socket.close();//关闭打开的socket // // } catch (Exception e) { // // TODO: handle exception // }finally{ // // socket.close();// // } try { DataInputStream in=new DataInputStream(socket.getInputStream());//接收客户端信息 String readline=in.readUTF(); System.out.println(readline); DataOutputStream out=new DataOutputStream(socket.getOutputStream()); //向客户端发送消息 out.writeUTF("link server success"); out.flush(); in.close(); //关闭流 out.close();//关闭流 socket.close();//关闭打开的socket } catch (Exception e) { System.out.println(e.getMessage()); } } } catch (IOException e) { System.out.println(e.getMessage()); } } } public static void main(String[] args) throws IOException { new Server(); //开启服务器 } }
客户端和服务器端保持长时间的通信,服务器需要不断的读取客户端数据,并向客户端写入数据,客户端也需要不断的读取服务器的数据
服务器应该为每个Socket单独启动一条线程,每条线程负责与一个客户端进行通信
服务器端:
package com.hust.multithred; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; public class MyServer { /** * @param args * @throws IOException */ //服务器端保存所有Socket的ArrayList public static ArrayList<Socket> socketlist=new ArrayList<Socket>(); public static void main(String[] args) throws IOException { // TODO Auto-generated method stub ServerSocket ss=new ServerSocket(3000);//ServerSocket监听3000端口 while(true){ Socket socket_in_server=ss.accept();//循环等待客户端的Socket socketlist.add(socket_in_server); //每接收到一个客户端的Socket,将服务器端产生的与之对应的Socket加入数组 //为每一个Socket单独启动一条线程,每个线程负责与一个客户端进行通信 SocketThread socketthread=new SocketThread(socket_in_server); new Thread(socketthread).start(); } } }
package com.hust.multithred; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Socket; public class SocketThread implements Runnable{//线程任务类,实现Runnable接口 Socket s=null; BufferedReader br=null; public SocketThread(Socket s) throws IOException{ this.s=s; br=new BufferedReader(new InputStreamReader(s.getInputStream()));//Socket输入流包装成字符流,来自客户端的数据在此输入流上,服务器端可以读 } public void run() { // TODO Auto-generated method stub try { String content=null; //循环不断冲Socket中读取客户端发送过来的数据 while((content=readFormClient())!=null){ //每读到数据之后,将读到的内容向每个Socket发送一次 for(Socket s:MyServer.socketlist){ OutputStream os=s.getOutputStream(); os.write((content+"\n").getBytes("utf-8")); //写到每个socket 的输出流上 } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //从输入流上读取来自客户端的数据方法 public String readFormClient(){ String content=null; try { content = br.readLine(); } catch (IOException e) { // TODO Auto-generated catch block MyServer.socketlist.remove(s); } return content; } }
MainActivity.java
package com.hust.multithreadclient; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends Activity { EditText input; TextView show; Button send; Handler handler; ClientThread clientthread; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); input=(EditText) findViewById(R.id.input); show=(TextView) findViewById(R.id.show); send=(Button) findViewById(R.id.send); //此处handler接收来自子线程的消息,负责处理消息,更新UI handler=new Handler(){ @Override //如果消息来自子线程 public void handleMessage(Message msg) { // TODO Auto-generated method stub if(msg.what==0x123){ show.append("\n"+msg.obj.toString()); } } }; //客户端启动ClientThread线程创建玩过连接,读取来自服务器的数据 new Thread(new ClientThread(handler)).start(); send.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { // 当用户按下发送按钮后,将用户输入的数据封装成Message,发给子线程的Handler,此处handler负责发送消息 Message msg=new Message(); msg.what=0x111; msg.obj=input.getText().toString(); clientthread.rvhandler.sendMessage(msg);//发给子线程的Handler input.setText(""); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
package com.hust.multithreadclient; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; import android.os.Handler; import android.os.Looper; import android.os.Message; public class ClientThread implements Runnable { Socket s; Handler handler; //定义向UI线程发送消息的Handler对象 Handler rvhandler; //定义接收UI线程消息的Handler对象 BufferedReader br=null; OutputStream os=null; public ClientThread(Handler handler){ this.handler=handler; } @Override public void run() { // TODO Auto-generated method stub try { s=new Socket("192.168.1.88",3000); br=new BufferedReader(new InputStreamReader(s.getInputStream())); os=s.getOutputStream(); //启动一条子线程来读取服务器端相应的数据 new Thread(){ @Override public void run() { // TODO Auto-generated method stub String content=null; try{ while((content=br.readLine())!=null){ Message msg=new Message(); msg.what=0x123; msg.obj=content; handler.sendMessage(msg);//此子线程中仅仅是读来自服务器的数据,并发给UI线程的Handler处理 } }catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }.start(); /* * 当前客户端线程中Handler,Android线程之间的通信是Handler来实现 * 此Hnadler接收UI线程发过来的数据,即用户的输入,并写到输出流 * 因为此Handler是接收处理消息,所以需要使用Looper * */ Looper.prepare(); rvhandler=new Handler(){ @Override public void handleMessage(Message msg) { //如果接收到UI线程中用户输入的数据 if(msg.what==0x111){ try{ //将用户在文本框内的输入内容写入网络 os.write((msg.obj.toString()+"\r\n").getBytes("utf-8")); }catch(IOException e){ e.printStackTrace(); } } } }; Looper.loop();//启动looper } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }