Socket和ServerSocket

来源:互联网 发布:linux cat vi 编辑:程序博客网 时间:2024/06/10 12:21

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,连接上服务器后,就可以开始发送信息,注意开启联网权限