关于Java Socket的使用以及多线程的客户端和服务器端之间的通信
Java的Socket与ServerSocket
Socket
指的是能够通过指定的ip和端口号与服务器互相通信的一个客户端/套接字,通常我们都用它来充当客户端。
ServerSocket
顾名思义,就是服务器用的一个套接字,用来接收连接到指定端口号的客户端/套接字。
Socke类 里面有几个比较重要的方法:
- 两参构造函数 Socket(String ip,int port)
我们能用它来创建一个连接到指定ip和端口号的套接字,用于与服务器通信 - 输出流 getOutputStream() 以及输入流 getInputStream()
我们可以用这两个方法来获取 客户端向服务器的请求 以及 来自服务器的响应 - Socket关闭方法 close()
我们可以用此方法关掉不用的通信,并释放相应的资源
ServerSocket类 里面也有几个比较重要的方法:
- 一参构造函数 ServerSocket(int port)
我们能用它来 创建一个监听指定端口号的服务器套接字,用于监听客户端的通信 - 获取客户端Socket的函数 accept()
我们可以用这个方法来获取 新连接上的客户端 。但是要注意,这个方法是以 阻塞的方式 来运行的,也就是一旦我们调用了这个方法,调用它的线程就会进入阻塞状态,一直等待客户端的连接。而服务器一般需要 同时提供多个客户端的连接需求,故我们一般会同时使用 多线程 来提高服务器的带机量。 - ServerSocket关闭方法 close()
我们可以用此方法关掉不用的服务器套接字,并释放相应的资源
多线程
在没学习多线程之前,我一直以为多线程肯定可以提升程序的运行速度,学完之后才发现,它不一定可以提升程序的运行速度,但是可以提高程序运行的效率,就好比一个人干活和一群人干活哪个效率高一样,多线程可以让我们的程序同时干多件事情,同时它也会带来线程安全的问题:
- Java的多线程有三种实现方式 ,分别是:
(1) 继承Thread类,重写run()方法
public class Test {
public static void main(String[] args) {
MyThread t = new MyThread();
t.start();
}
}
class MyThread extends Thread {
private void say() {
System.out.println(Thread.currentThread().getName() + " hello java");
}
@Override
public void run() {
say();
}
}
(2) 实现Runnable接口,实现run()方法
public class Test {
public static void main(String[] args) {
MyRunnable r = new MyRunnable();
new Thread(r).start();
}
}
class MyRunnable implements Runnable {
private void say() {
System.out.println(Thread.currentThread().getName() + " hello java");
}
@Override
public void run() {
say();
}
}
(3) 实现Callable接口,实现call()方法
public class Test {
public static void main(String[] args) {
MyCallable r = new MyCallable();
FutureTask f = new FutureTask(r);
new Thread(f).start();
try {
System.out.println(r.call());
} catch (Exception e) {
e.printStackTrace();
}
}
}
class MyCallable implements Callable {
private void say() {
System.out.println(Thread.currentThread().getName() + " hello java");
}
@Override
public Object call() throws Exception {
say();
Thread.sleep(1000*5);
return "call is execute";
}
}
//输出
main hello java
//若不调用call()方法,则和普通的Runnable一样
Thread-0 hello java
//若调用call()方法,则调用者会等待其返回结果
call is execute
因为都是无参方法,可以使用lambda表达式进行简化。
new Thread(()->{
//里面相当于run
System.out.println(Thread.currentThread().getName()+"已经启动!");
}).start();
使用案例
这是我写的一个服务器端和一个客户端,这里面都使用到了多线程。
客户端
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class MyClient implements Runnable{
private Socket client;
public MyClient(String ip,int port){
//判断如果ip不为空,且端口号大于0 小于65536
if(!ip.isEmpty() && port>0 && port<65536)