- Socket默认使用TCP协议
1. 项目目录
* 1.1 SocketClient.java源码*
package socket.base;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
/**
* 此例子客户端和服务器之间只有一个通讯线程,所以它们之间只有一条Socket信道。
*
* 运行时要先开启服务器端的程序再开启客户端,即先跑SocketServer的main()方法,再跑SocketClient的main()方法,
* server端会等待client端连接。如果先启动客户端程序,客户端程序会找不到服务端程序而异常
*/
public class SocketClient {
static String clientName = "Mike";
// 端口号,这里给出的端口号必须要和服务器端的一致。
public static int portNo = 3333;
/**
* 根据地址信息“localhost”,创建一个InetAddress类型的对象addr。
* 这里,因为我们把客户端和服务器端的代码都放在本机运行,所以同样可以用“127.0.0.1”字符串,来创建InetAddress对象。
*/
public static void main(String[] args) throws IOException {
// 设置连接地址类,连接本地
InetAddress addr = InetAddress.getByName("localhost");
// 根据addr和端口号信息,创建一个Socket类型对象,该对象用来同服务器端的ServerSocket类型对象交互,共同完成C/S通讯流程。
Socket socket = new Socket(addr, portNo);
try {
System.out.println("socket = " + socket);
// 创建in和out两类IO句柄,用来向服务器端发送和接收数据流。
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
// 通过out对象,向服务器端发送"Hello Server,I am …"的字符串。发送后,用in句柄,接收从服务器端的消息。
out.println("Hello Server,I am " + clientName);
// 读取服务器端返回内容
String str = in.readLine();
System.out.println(str);
// 利用out对象,发送”byebye”字符串,用以告之服务器端,本次通讯结束。
out.println("byebye");
} finally {
System.out.println("close the Client socket and the io.");
// 关闭Socket对象,断开同服务器端的连接。
socket.close();
}
}
}
* 1.2 SocketServer.java源码*
package socket.base;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
/**
* socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过"套接字"向网络发出请求或者应答网络请求。
* 开发原理:
* 服务器,使用ServerSocket监听指定的端口,端口可以随意指定(由于1024以下的端口通常属于保留端口,在一些操作系统中不可以随意使用,
* 所以建议使用大于1024的端口),等待客户连接请求,客户连接后,会话产生;在完成会话后,关闭连接。
* 客户端,使用Socket对网络上某一个服务器的某一个端口发出连接请求,一旦连接成功,打开会话;会话完成后,关闭Socket。客户端不需要指定打开的端口,
* 通常临时的、动态的分配一个1024以上的端口。
*/
public class SocketServer {
// 设置通讯所用到的端口号
public static int portNo = 3333;
/**
* 根据给定端口号,初始化一个ServerSocket对象serverSocket
* 该对象用来承担服务器端监听连接和提供通讯服务的功能。
*/
public static void main(String[] args) throws IOException {
// 启动一个 Socket Server 并指定监听端口
ServerSocket serverSocket = new ServerSocket(portNo);
System.out.println("The Server is start: " + serverSocket);
/*
* Accept()方法用于产生"阻塞",直到接受到一个连接,并且返回一个客户端的Socket对象实例。
* "阻塞"是一个术语,它使程序运行暂时"停留"在这个地方,直到一个会话产生,然后程序继续;通常"阻塞"是由循环产生的。
* 即当调用accept方法后,整段服务器端代码将会阻塞在这里,直到客户端发来connect请求。
*/
// 阻塞,直到有客户端连接,监听从客户端的连接请求。
Socket socket = serverSocket.accept();
try {
System.out.println("Accept the Client: " + socket);
// 创建两个名为in和out的对象,用来传输和接收通讯时的数据流。
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
// 创建一个while(true)的无限循环,在这个循环里,通过in.readLine()方法,读取从客户端发送来的IO流(字符串),并打印出来。
while (true) {
String str = in.readLine();
// 如果读到的字符串是“byebye”,那么退出while循环。
if ("byebye".equals(str)) {
break;
}
System.out.println("In Server reveived the info: " + str);
out.println(str);
}
} finally {
// 在try…catch…finally语句段里,不论在try语句段里是否发生异常,并且不论这些异常的种类,finally从句都将会被执行到。
System.out.println("close the Server socket and the io.");
// 关闭描述客户端的连接句柄socket对象和serverSocket对象。
socket.close();
serverSocket.close();
}
}