Socket的学习

Socket

Java中客户端通常使用Socket的构造器来连接到指定的服务端,

服务端的ServerSocketaccept方法接收到Socket连接后也会产生一个Socket对象,
此时就不存在客户端和服务端,他们就变成两个Socket的交流。
在这里插入图片描述

ServerSocket的一些方法

方法说明
Socket accept()如果接收到客户端的Socket的连接请求,该方法返回一个与连接客户端Socket对应的Socket,否则该方法一直处于等待状态,线程也被阻塞。
ServerSocket(int port)(构造器)指定端口port来创建一个ServerSocket
ServerSocket(int port, int backlog)(构造器)增加一个改变队列长度的参数backlog
ServerSocket(int port, int backlog, InetAddress localAddr)(构造器)在机器存在多个IP的情况下,通过localAddr指定IP地址
close()关闭服务器

Socket的一些方法

方法说明
Socket(InetAddress/String remoteAddress, int port)(构造器)创建连接到指定IP和端口远程主机的Socket,默认使用本地主机的默认ip,系统动态分配的端口
Socket(InetAddress/String remoteAddress, int port, InetAddress localAddr, int localPort)(构造器)创建连接到指定IP和端口远程主机的Socket,同时指定本地主机的ip和端口
Socket()(构造器)未连接的Socket
void connect(SocketAddress address)连接到指定地址
void connect(SocketAddress address, int timeoutInMilliseconds)连接到指定地址,若给定时间内没响应,则返回
void setSoTimeout(int timeoutInMilliseconds)给定一个读请求的阻塞时间,超时则抛异常InterruptedIOException
boolean isConnected()如果已被连接,则返回true
boolean closed()关闭Socket
InputStream getInputStream()返回该Socket对象对应的输入流,让程序通过该输入流从Socket中读取数据
OutputStream getOutputStream()返回该Socket对象对应的输出流,让程序通过该输出流向Socket中输出数据

下面使用Socket制作一个简易的聊天室

服务端,这是一个纯java项目(我使用的是IntelliJ IDEA Community Edition 2021.2):
ServerThread.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;

public class ServerThread implements Runnable{

    //定义当前线程要处理的Socket
    Socket s = null;
    //当前线程要处理的Socket对应的输入流
    BufferedReader br = null;

    //该线程的构造器,参数为连接客户端的Socket
    public ServerThread(Socket s) throws IOException {
        this.s = s;
        //取Socket的输入流
        br = new BufferedReader(
                new InputStreamReader(
                        s.getInputStream(), "utf-8"));
    }

    public void run() {
        try {
            String content = null;
            //循环,不断从该Socket读消息
            while((content = readFromClient()) != null) {
                System.out.println(content);//这里做了打印操作,看下客户端的数据是否传过来了
                //循环,给所有的已连接的Socket都传递该Socket的消息
                for(Iterator<Socket> it = MyServer.socketArrayList.iterator(); it.hasNext(); ) {
                    Socket s = it.next();
                    try {
                        //取该Socket的输出流,赋值content + "\n"
                        OutputStream os = s.getOutputStream();
                        os.write((content + "\n").getBytes(StandardCharsets.UTF_8));
                    }catch (SocketException e) {
                        e.printStackTrace();
                        it.remove();
                        System.out.println(MyServer.socketArrayList);
                    }
                }
            }
        }catch (IOException e) {
            e.printStackTrace();
        }
    }

    private String readFromClient() {
        try {
            return br.readLine();
        }catch (IOException e) {
            e.printStackTrace();
            MyServer.socketArrayList.remove(s);
        }
        return null;
    }
}

MyServer.java

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class MyServer {
    //定义保存所有的Socket的ArrayList
    public static ArrayList<Socket> socketArrayList = new ArrayList<Socket>();
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(30000);
        while(true) {
            //此行代码会阻塞,一直等待别人连接
            Socket s = ss.accept();
            socketArrayList.add(s);
            //每当客户端启动后启动一条线程为该客户端服务
            new Thread(new ServerThread(s)).start();
        }
    }
}

客户端,Android项目:
activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <EditText
            android:id="@+id/input"
            android:layout_width="280dp"
            android:layout_height="wrap_content" />
        <Button
            android:id="@+id/send"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingLeft="8dp"
            android:text="发送" />
    </LinearLayout>
    <TextView
        android:id="@+id/show"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="top"
        android:background="#ffff"
        android:textSize="14dp"
        android:textColor="#f000" />
</LinearLayout>

ClientThread.java

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketTimeoutException;

public class ClientThread implements Runnable {

    //客户端的IP,这里是我本地的IP地址,我打了马赛克了
    private final static String IP = "***.**.**.*";
    private Socket s;
    //这个Handler读到服务端的信息后向UI线程发消息
    private Handler handler;
    //这个Handler本地点击发送信息后向服务器发消息
    public Handler revHandler;
    BufferedReader br = null;
    OutputStream os = null;

    public ClientThread(Handler handler) {
        this.handler = handler;
    }

    public void run() {
        try {
            s = new Socket(IP, 30000);
            br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            os = s.getOutputStream();
            new Thread() {
                public void run() {
                    String content = null;
                    try {
                        while((content = br.readLine()) != null) {
                            Message msg = new Message();
                            msg.what = 0x123;
                            msg.obj = content;
                            handler.sendMessage(msg);
                        }
                    }catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }.start();
            Looper.prepare();
            revHandler = new Handler() {
                public void handleMessage(Message msg) {
                    if(msg.what == 0x345) {
                        try {
                            os.write((msg.obj.toString() + "\r\n").getBytes("utf-8"));
                        }catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            };
            Looper.loop();
        }catch (SocketTimeoutException e) {
            System.out.println("网络连接超时");
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

MainActivity.java

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    EditText input;
    Button send;
    TextView show;
    Handler handler;
    ClientThread clientThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        input = findViewById(R.id.input);
        send = findViewById(R.id.send);
        show = findViewById(R.id.show);
        handler = new Handler() {
            public void handleMessage(Message msg) {
                if(msg.what == 0x123) {
                    show.append("\n" + msg.obj.toString());
                }
            }
        };
        clientThread = new ClientThread(handler);
        new Thread(clientThread).start();
        send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    Message msg = new Message();
                    msg.what = 0x345;
                    msg.obj = input.getText().toString();
                    clientThread.revHandler.sendMessage(msg);
                    input.setText("");
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

然后AndroidManifest.xml还得加上联网权限

<uses-permission android:name="android.permission.INTERNET"/>

然后服务器,客户端一起运行
客户端手机每发送一条消息都会显示,服务端也能看到打印
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值