Socket本质上就是Java封装了传输层上的TCP协议(注:UDP用的是DatagramSocket类)。要实现Socket的传输,需要构建客户端和服务器端。另外,传输的数据可以是字符串和字节。字符串传输主要用于简单的应用,比较复杂的应用(比如Java和C++进行通信),往往需要构建自己的应用层规则(类似于应用层协议),并用字节来传输。
直接上代码
public class MyServerSocket {
private Vector vector=new Vector();//存放所有的客户端socket
public MyServerSocket()
{
try{
ServerSocket serverSocket=new ServerSocket(23);//服务端开启对端口13345的监听
while(true){
Socket socket=serverSocket.accept();//服务器端提供与客户端相对应的socket
// JOptionPane.showMessageDialog(null, "已经有客户端连入");
ChatSocket cs=new ChatSocket(socket,vector);//对每一个客户端都提供一个ChatSocket类来进行信息的交互
add(cs);
cs.start();
}
} catch (IOException e){
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
public void add(ChatSocket csSocket)//服务器端添加每一个客户端socket
{
vector.add(csSocket);
}
public static void main(String[]args)
{
new MyServerSocket();
}
}
public class ChatSocket extends Thread {
Socket socket;
Vector vector;
public ChatSocket(Socket s,Vectorvector)
{
this.socket=s;
this.vector = vector;
}
public void out(String out)//服务器发送消息给客户端
{
try
{
BufferedWriter bfWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bfWriter.write(out);
System.out.println(out + "--00-");
bfWriter.flush();//清空缓冲区,避免消息延迟显示
} catch (UnsupportedEncodingException e)
{
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (IOException e)
{
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
@Override
public void run()
{
try
{
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
while((line=bufferedReader.readLine())!=null)//服务端接收客户端的消息
{
// sendMessage(this, line);//转发给其他客户端
// System.out.println(line + "---");
BufferedWriter bfWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bfWriter.write(line);
System.out.println(line + "--00-");
bfWriter.flush();//清空缓冲区,避免消息延迟显示
}
// bufferedReader.close();
} catch (IOException e)
{
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
public void sendMessage(ChatSocket cs,String out)
{
for(int i=0;iout.println(out + "==");
ChatSocket csChatSocket= vector.get(i);
if(!cs.equals(csChatSocket))//将发送该消息的客户端除外
{
csChatSocket.out(out);
}
}
}
}
public class SocketActivity extends Activity {
Button conBtn;
EditText ipText;
EditText point_text;
Button sendBtn;
EditText sendText;
TextView textView;
Socket clientSocket;
BufferedReader bfReader;
BufferedWriter bfWriter;
private String ipStr = "192.168.2.32";
private int ipStrProt = 2233;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.socket);
findViews();
conBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ipStr = ipText.getText().toString();
ipStrProt = Integer.parseInt(point_text.getText().toString());
if (ipStr.equals("") || ipStrProt == 0 ){
Toast.makeText(SocketActivity.this,"请输入IP和端口号",Toast.LENGTH_SHORT).show();
}else {
connect();
}
}
});
sendBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
send();
}
});
}
private void findViews(){
conBtn = (Button)findViewById(R.id.con_btn);
sendBtn = (Button)findViewById(R.id.send_btn);
ipText = (EditText)findViewById(R.id.ip_text);
point_text = (EditText)findViewById(R.id.point_text);
sendText = (EditText)findViewById(R.id.send_text);
textView = (TextView)findViewById(R.id.content_text);
}
private void connect(){
AsyncTask reader = new AsyncTask() {
@Override
protected Void doInBackground(Void... params) {
try {
Log.e("ip",ipStr + "-" + ipStrProt);
clientSocket = new Socket(ipStr,ipStrProt);
//客户端建立与服务端socket的连接,"10.62.37.152"为我的局域网ip地址,读者按照自己的ip地址进行相应修改
bfWriter = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
// bfReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
publishProgress("success");
while(clientSocket.isConnected() && !clientSocket.isClosed()){//isConnected 代表是否连接成功过
InputStream isRead = clientSocket.getInputStream();
// 缓冲区
byte[] buffer = new byte[isRead.available()];
// 读取缓冲区
isRead.read(buffer);
// 转换为字符串
String responseInfo = new String(buffer);
Log.e("Socket Server", responseInfo);
// 日志中输出
if (!responseInfo.equals("")){
publishProgress(responseInfo);
}
}
// publishProgress("success");
// String line = "hello";
// while(true){
// line = bfReader.readLine();
// Log.e("message",line);
// publishProgress(line);//接收从服务端转发来的消息
// }
} catch (Exception e) {
e.printStackTrace();
publishProgress("链接建立失败" + "--"+e.toString());
Log.e("SocketActivity",e.toString());
}
return null;
}
@Override
protected void onProgressUpdate(String... values) {
if (values[0] == "success") {
Toast.makeText(SocketActivity.this, "链接建立成功",
Toast.LENGTH_SHORT).show();
}
textView.append("别人说:" + values[0] + "\n");
super.onProgressUpdate(values);
}
};
reader.execute();
}
//发送消息给服务端
private void send(){
try {
textView.append("我说"+sendText.getText().toString()+"\n");
bfWriter.write(sendText.getText().toString() + "\n");
bfWriter.flush();
} catch (IOException e) {
Toast.makeText(getApplicationContext(),"无法建立连接",Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
private void end(Socket serverSocket){
/* * * * * * * * * * Socket 客户端读取服务器端响应数据 * * * * * * * * * */
try {
// serverSocket.isConnected 代表是否连接成功过
// 判断 Socket 是否处于连接状态
if(true == serverSocket.isConnected() && false == serverSocket.isClosed()) {
// 客户端接收服务器端的响应,读取服务器端向客户端的输入流
InputStream isRead = serverSocket.getInputStream();
// 缓冲区
byte[] buffer = new byte[isRead.available()];
// 读取缓冲区
isRead.read(buffer);
// 转换为字符串
String responseInfo = new String(buffer);
// 日志中输出
Log.e("Socket Server", responseInfo);
}
// 关闭网络
serverSocket.close();
}
catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="@+id/ip_text"
android:text="192.168.12.46"
android:hint="输入IP地址"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/point_text"
android:text="2223"
android:hint="输入端口号地址"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/con_btn"
android:text="Connect"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_width="match_parent"
android:layout_height="280dp"
android:id="@+id/content_text"/>
<EditText
android:id="@+id/send_text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:text="send"
android:id="@+id/send_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
LinearLayout>
可能你会觉得Socket很简单,是的,确实很简单,当时我也是觉得很简单的。很快就遇到问题了,客户端可以向服务端发消息,但是服务端发的消息客户端接收不到,通过调试发现在
bfReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
bfReader.readLine()
这里阻塞了,一直读不出来服务端的信息,后来通过自己的猜想,换一种方式读取接没问题了:
while(clientSocket.isConnected() && !clientSocket.isClosed()){//isConnected 代表是否连接成功过
InputStream isRead = clientSocket.getInputStream();
// 缓冲区
byte[] buffer = new byte[isRead.available()];
// 读取缓冲区
isRead.read(buffer);
// 转换为字符串
String responseInfo = new String(buffer);
Log.e("Socket Server", responseInfo);
// 日志中输出
if (!responseInfo.equals("")){
publishProgress(responseInfo);
}
}
以上内容是小编给大家分享的Android Socket通信详解的相关知识,希望大家喜欢。