Socket概念:socket是一套用于不同主机间通信的API,它工作在我们TCP/IP协议栈上。
若要通过socket与不同主机之间建立通信,需要指定主机的一个ip地址和一个端口号,(ip地址用于唯一标识你的网络设备,端口用于区分主机上不同的应用)
通过socket,可以建立一条不同主机之间的虚拟数据通道 ,并且是点对点(应用对应用)的,可以想象为一条数据线连接到不同应用的插槽上。
TCP and UDP
TCP:Transmission Control Protocol 传输控制协议(基于数据流Data Stream的协议)
两个特点:
1.可靠,它的底层会自动检测并回传丢失的数据包——意思,你发送的数据对方一定会接受到。
2.稳定,发送和接受到的数据顺序是一致的。比如,你发送的一串字符“HELLO”,对方接受到的字符是完全一样的。
注意:TCP要求收发数据的双方扮演不同的角色:服务器和客户端,服务器会被动等待客户端的连接,他不会主动发起请求。
UDP:User Datagram Protocol 用户报文协议
以报文(Datagrm)为单位来收发数据,并且UDP不会自动回传丢失的数据包,因此不保证数据一定能被对方接受到,也正因为少了这些检查,UDP通常拥有更低的延迟并且占用更少的系统资源,它更适合像视频语言通话这种实时性较高的应用。
Stream:java中分为字节流(byte streams)和字符流(character streams)
byte streams:机器格式数据,数据由0和1组成,人看不懂。好处:非常高效
character streams:人可以读懂,需要机器翻译但比较慢。
Socket在编程中的应用:
编程时需要加的包:import java.net.*;
如何通过java查询已知域名的地址,如:“www.qmul.ac.uk"
socket会为程序员提供一个stream,因此你不需要担心网络如何send bytes,你只需要与数据流进行交互
(C/S架构)Servers and Clients:
![](https://i-blog.csdnimg.cn/blog_migrate/a9d5e5dbe6c6309865ddf227e3eb2a3d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/db6f43d9956f0a076f88189400218ad4.png)
一个简单的服务器和客户端:Server and Client
服务端的socket程序分成两个模块,即等待连接模块和负责与客户端通信的模块 。当服务器程序启动并读取配置文件完成初始化操作后,就会运行等待连接模块。这个模块会创建套接字,然后进入等待连接的暂停状态。接下来,当 客户端连发起连接时,这个模块会恢复运行并接受连接,然后启动客户端通信模块,并移交完成连接的套接字。接下来,客户端通信模块就会使用已连接的套接字与客户端进行通信,通信结束后,这个模块就退出了。
Server服务端代码:
import java.net.*;
import java.io.*;
public class Server {
public static final int PORT = 2333;
public static void main(String[] args) throws Exception {
ServerSocket s = new ServerSocket(PORT);
System.out.println("start");
try {
Socket socket = s.accept();// 等待有人接入 阻塞blocked
try {
System.out.println("conect:" + socket);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),
true);
while (true) {
String str = in.readLine();
if (str == "null" || str.equals("END")) {
break;
} else {
System.out.println("Echoing:" + str);
out.println(str);
}
}
} finally {
System.out.println("closing....");
socket.close();
}
} finally {
s.close();
}
}
}
Client客户端代码:
import java.net.*;
import java.io.*;
public class Client {
public static final int PORT = 2333;
public static void main(String[] args) throws Exception {
InetAddress addr = InetAddress.getByName(null);
System.out.println("addr=" + addr);
Socket socket = new Socket(addr, 2333);
try {
System.out.println("socket:" + socket);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),
true);
for (int i = 1; i <= 10; i++) {
out.println("Message" + i);
String str = in.readLine();
System.out.println(str);
}
out.println("END");
} finally {
socket.close();
}
}
}
其中,ServerSocket 和 socket的区别:SeverSocket用accept()方法等待客户端接入,然后产生一个socket,然后通过这个socket去与其他客户进行连接、通信。
注意:以上两段代码全背!!!!!
局限性:以上情况只能一次处理一个客户端,但往往我们需要同时处理多个客户端。例如上述情况,我的服务端连接到我的服务器之后,我的服务端一结束,我的服务器也没了。比如我登陆QQ连接了腾讯的服务器,当我把我的QQ关闭后,腾讯的服务器也没了,这个问题就很尴尬。
于是,写一个MultiSever的类:可以给多个用户服务(弱化版,一次给一个人服务,服务完之后又进入等待状态,而不是结束)
import java.net.*;
import java.io.*;
public class MultiServer {
public static final int PORT = 2333;
public static void main(String[] args) throws Exception {
ServerSocket s = new ServerSocket(PORT);
System.out.println("start");
while (true) {
try {
Socket socket = s.accept();// 等待有人接入 阻塞blocked
try {
System.out.println("conect:" + socket);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(
new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),
true);
while (true) {
String str = in.readLine();
if (str == "null" || str.equals("END")) {
break;
} else {
System.out.println("Echoing:" + str);
out.println(str);
}
}
} finally {
System.out.println("closing....");
socket.close();
}
} finally {
}
}
}
}
相比较于Server,多加了一个while(true) 即可无限循环服务
强化版,多线程:
import java.net.*;
import java.io.*;
class ClientThread extends Thread {
private Socket socket;
private BufferedReader in;
private PrintWriter out;
private static int counter = 0;
private int id = counter++;
private static int threadcount = 0;
public static int threadCount() {
return threadcount;
}
public ClientThread(InetAddress addr) {
System.out.println("Making client" + id);
threadcount++;
try {
socket = new Socket(addr, MultiServer.PORT);
} catch (IOException e) {
System.err.println("Socket failed");
}
try {
in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(
socket.getOutputStream())),
true);
start();
} catch (IOException e) {
try {
socket.close();
} catch (IOException e2) {
System.err.println("Socket not closed");
}
}
}
public void run() {
try {
for (int i = 0; i < 5; i++) {
out.println("Client :" + id + ": " + i);
String str = in.readLine();
System.out.println(str);
}
out.println("END");
} catch (IOException e) {
System.err.println("IO Exception");
} finally {
try {
socket.close();
} catch (IOException e) {
System.err.println("Socket not closed");
}
threadcount--;
}
}
}
import java.net.*;
import java.io.*;
//多线程,强化版
public class MultiClient {
static final int MAX_THREADS = 40;
public static void main(String[] args) throws IOException, InterruptedException {
InetAddress addr = InetAddress.getByName(null);
while (true) {
if (ClientThread.threadCount() < MAX_THREADS)
new ClientThread(addr);
Thread.currentThread().sleep(100);
}
}
}