创建服务器端的步骤:
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();
}
}
在客户端:
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 socketlist=new ArrayList();
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();
}
}
}