Socket和ServerSocket主要是使用在服务器编程这一块,完成客户端与服务端连接的建立以及数据通信,客户端与服务端的连接需要服务端的IP和连接对应的端口号,客户端发送请求,服务端接收请求并反馈信息给客户端,客户端对响应解析,拿到数据并呈现在界面中,客户端和服务端的这种关系叫CS架构。
Socket和ServerSocket类是在V7包中的,类的作用是封装,封装属性和方法,因为socket通信需要用到IP和端口号,故Socket类中封装了IP和端口号,还有建立连接的方法和使用到的流。
先有服务端,再有客户端,服务端使用到的是ServerSocket类,用于接收客户端发送的连接请求:
ServerSocket ss=new ServerSocket(port);//port是个端口号,客户端连接服务端的时候,要提供一个端口号,表示你要访问的是服务器中的哪个端口,port的范围是0~65535
ss.accept();//(阻塞式)接收客户端的连接
阻塞式解析:当没有客户端请求的时候,服务器就在这里等,即阻塞在这条语句中,一旦有了客户端的请求,服务器立马接收请求,从这条语句开始执行,实际上是主线程阻塞在这里,当有请求的时候,在此开启子线程执行,主线程依然阻塞在这里等待。
String Ip="你要访问的服务器的IP地址";
int port="你要访问的服务器的某一个端口号";
Socket socket=new Socket(Ip,port);
举个例子:
服务端Java代码:
package cn.tedu; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.List; /** * 群聊天室 服务端 */ public class ChatServer { private List<Socket> sockets = new ArrayList<Socket>(); /** * 启动聊天室服务器 * @throws IOException */ public void startServer() throws IOException{ int port = 8888; ServerSocket ss = new ServerSocket(port); while(true){ Socket socket = ss.accept(); //连接已经建立成功 //把socket对象存入集合中 以后使用 sockets.add(socket); System.out.println("连接成功:"+socket.getInetAddress()); //启动工作线程 处理相应客户端的消息业务 new WorkThread(socket).start(); } } /** * 工作线程 处理与客户端的消息操作 * 接收客户端的信息 * 给已经连接到服务器的每一个客户端发送消息 */ class WorkThread extends Thread{ private Socket socket; public WorkThread(Socket socket) { this.socket = socket; } @Override public void run() { try { DataInputStream dis = new DataInputStream(socket.getInputStream()); while(true){ //读取客户端发过来的消息 String message=dis.readUTF(); //给每一个客户端都写一遍 for(Socket s : sockets){ DataOutputStream dos = new DataOutputStream(s.getOutputStream()); dos.writeUTF(message); dos.flush(); } } } catch (IOException e) { e.printStackTrace(); //服务端处理这个客户端请求时出错了 //需要把集合中的socket对象给移除 sockets.remove(socket); } } } public static void main(String[] args) { ChatServer server = new ChatServer(); try { System.out.println("服务启动成功...."); server.startServer(); } catch (IOException e) { e.printStackTrace(); } } } 客户端AndroidAPP:
package cn.tedu.android_day01_chatclient; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.app.Activity; import android.view.Menu; import android.view.View; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; public class MainActivity extends Activity { private EditText etIp; private EditText etText; private Button btnConnect; private Socket socket; private DataInputStream dis; private DataOutputStream dos; private ListView listView; private List<String> messages = new ArrayList<String>(); private ArrayAdapter<String> adapter; // 声明Handler对象 处理消息 private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { switch (msg.what) { case HANDLER_RECEIVE_MESSAGE: //接收到了服务端发送过来的消息 String message=(String) msg.obj; //给listView更新Adapter messages.add(message); adapter.notifyDataSetChanged(); listView.setSelection(messages.size()-1); break; case HANDLER_CONNECT_SUCCESS: // 连接成功 etIp.setEnabled(false); btnConnect.setEnabled(false); break; } } }; public static final int HANDLER_CONNECT_SUCCESS = 1; public static final int HANDLER_RECEIVE_MESSAGE=2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 控件初始化 setViews(); setAdapter(); } /** * 初始化listView */ private void setAdapter() { adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, messages); listView.setAdapter(adapter); } /** * 监听 */ public void doClick(View view) { switch (view.getId()) { case R.id.btnConnect: // 点击了建立连接 new Thread() { public void run() { try { // 建立连接 connect(); } catch (IOException e) { e.printStackTrace(); } } }.start(); break; case R.id.btnSend: // 发送消息 new Thread() { public void run() { try { sendMessage(); } catch (IOException e) { e.printStackTrace(); } } }.start(); break; } } /** * 发送消息 工作线程中执行 */ private void sendMessage() throws IOException { String text = etText.getText().toString(); dos.writeUTF("李雷:\n"+text); dos.flush(); } // 建立连接 在工作线程中执行 private void connect() throws IOException { String ip = etIp.getText().toString(); socket = new Socket(ip, 8888); dis = new DataInputStream(socket.getInputStream()); dos = new DataOutputStream(socket.getOutputStream()); // 连接建立成功 把etIp与btnConnect不可用 handler.sendEmptyMessage(HANDLER_CONNECT_SUCCESS); // 启动工作线程 用于读取服务端写给客户端的消息 new ReadThread().start(); } /** * 初始化 */ private void setViews() { etIp = (EditText) findViewById(R.id.etIp); etText = (EditText) findViewById(R.id.etText); btnConnect = (Button) findViewById(R.id.btnConnect); listView = (ListView) findViewById(R.id.listView); } /** * 不断的读取消息的工作线程 */ class ReadThread extends Thread { @Override public void run() { try { while (true) { String message = dis.readUTF(); //消息已经接收 需要更新ListView //发消息给handler 让handler在主线程中更新 Message msg = new Message(); msg.what = HANDLER_RECEIVE_MESSAGE; msg.obj = message; handler.sendMessage(msg); } } catch (IOException e) { e.printStackTrace(); } } } @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; } } 先运行服务端Java代码,再安装APP,连接上服务器后,就可以开始发送信息,注意开启联网权限
