一、项目描述
支持单客户端和服务器端的通信。
二、项目功能
客户端和服务器端相互发送信息、接收信息。
三、项目开发环境
IntelliJ IDEA
四、项目技术
Java基础、网络编程、JavaIO、Maven管理。
五、项目分析
套接字:TCP用主机的IP地址加上主机上的端口号作为TCP连接的端点,这种端点就叫做套接字(socket)或插口。套接字用(IP地址:端口号)表示。
5.1 服务端和客户端的连接
根据Socket类(客户端)和ServerSocket类(服务器端)的构造函数,客户端和服务器端要想通信,则由这两个类构成对象的端口地址(即IP地址)应相同。这样客户端和服务器端就建立了联系,服务器端首先启动,然后调用accept()等待客户端连接,accept()函数会一直阻塞直到连接到客户端为止。当客户端的IP地址和服务器端相同时,客户端启动即与服务器端进行连接。
IP地址和端口号除人为设定外,还可以通过在运行时设置main函数参数来设定。
5.2客户端和服务端的通信
首先要明确一点,客户端的Socket对象和服务器端接收的Socket对象不是同一个!因为它们分别要进行读数据和写数据,二者之间的读写是互不干扰的。客户端的Socket对象假设是client,服务器端接收的Socket对象假设是server。client读数据,对于客户端来说是输入流,而对于server来说是输出流。同样,client写数据,对于客户端来说是输出流,对于server来说是输入流。
因此,二者的写数据和读数据互不干扰。写数据可以通过OutputStream类和OutputStreamWriter类中的方法写,读数据可以通过InputStream类和Scanner类的方法去读。
5.3客户端的关闭
一般客户端可以根据用户的选择决定是否关闭,关闭的时候不仅包括客户本身,还有客户端的输出流和输入流,而服务器端一般不会关闭。
六、项目流程
1.创建项目(最好选择Maven项目)--chatroom
2.创建两个模块,分别为chat-room-server和chat-room-client。
3.在两个模块中分别创建主类(SingleThreadServer和SingleTnreadClient)
4.服务器端(SingleThreadServer)
4.1创建ServerSocket对象。
4.2接收客户端。
4.3接收客户端信息。
4.4发送信息。
所用到的函数及其功能如下:
//创建ServerSocket对象
1.public ServerSocket(int port) 创建绑定到指定端口的服务器套接字。
2.public SocketAddress getLocalSocketAddress() 返回此套接字绑定到的端点的地址。
//接收客户端对象
3.public Socket accept() throws IOException 侦听要连接到此套接字并接受它。 该方法将阻塞直到建立连接。
4.public SocketAddress getRemoteSocketAddress() 返回此套接字连接,或端点的地址null如果是未连接。
//接收信息
5.public InputStream getInputStream()throws IOException 返回此套接字的输入流。
6.Scanner(InputStream source) 构造一个新的 Scanner ,产生从指定输入流扫描的值。
7.public String nextLine() 将此扫描仪推进到当前行并返回跳过的输入,它可以缓冲搜索行的所有输入。
//发送信息
8.public OutputStream getOutputStream() throws IOException 返回此套接字的输出流。如果此套接字具有相关联的通道,则生成的输出流将其所有操作委派给通道。 如果通道处于非阻塞模式,则输出流的write操作将抛出IllegalBlockingModeException。
9.public OutputStreamWriter(OutputStream out) 创建一个使用默认字符编码的OutputStreamWriter。
5.客户端(SingleTnreadClient)
5.1准备Socket对象
5.2接收信息
5.3发送信息
5.4关闭客户端(包括Socket对象,输入流和输出流)
所用到的函数和功能如下:
//创建Socket对象
1.public Socket(InetAddress address,int port) throws IOException 创建流套接字并将其连接到指定IP地址的指定端口号。
//接收信息
2.public InputStream getInputStream()throws IOException 返回此套接字的输入流。
3.Scanner(InputStream source) 构造一个新的 Scanner ,产生从指定输入流扫描的值。
4.public String nextLine() 将此扫描仪推进到当前行并返回跳过的输入,它可以缓冲搜索行的所有输入。
//发送信息
5.public OutputStream getOutputStream() throws IOException 返回此套接字的输出流。如果此套接字具有相关联的通道,则生成的输出流将其所有操作委派给通道。 如果通道处于非阻塞模式,则输出流的write操作将抛出IllegalBlockingModeException。
6.public OutputStreamWriter(OutputStream out) 创建一个使用默认字符编码的OutputStreamWriter。
//关闭
7.public void close() throws IOException 关闭此套接字。
8.public void close() throws IOException 关闭此输入流并释放与流相关联的任何系统资源。 该close的方法InputStream什么都不做。
9.public void close() throws IOException 关闭此输出流并释放与此流相关联的任何系统资源。 close的一般合同是关闭输出流。 封闭流不能执行输出操作,无法重新打开。
6.测试
7.打包
七、代码实现
package SingleThread;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class SingleThreadServer {
public static void main(String[] args) throws IOException {
int port=7777;
//通过设置main函数参数设置端口号
if(args.length>0){
port=Integer.parseInt(args[0]);//把字符串类型的数据转为int型。
}
//1.创建ServerSocket对象
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("服务器启动:" + serverSocket.getLocalSocketAddress());//返回此套接字在其上侦听的端口地址(host)
//2.等待客户端连接
System.out.println("等待客户端连接。。。。。。\n");
Socket clientSocket = serverSocket.accept();//侦听并接收到此套接字的连接
System.out.println("客户端信息:" + clientSocket.getRemoteSocketAddress());//返回此套接字连接的端口地址
//3.接收数据,发送数据
//3.1接收数据
InputStream clientInput = clientSocket.getInputStream();//返回此套接字的输入流
Scanner scanner = new Scanner(clientInput);
String clientData = scanner.nextLine();//读取客户端的信息
System.out.println("来自客户端的信息:" + clientData);
//3.2发送数据
OutputStream clientOutput = clientSocket.getOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(clientOutput);
writer.write("你好,欢迎连接服务器\n");//用户读取到的数据
writer.flush();//flush()强制把缓冲区的数据写到输出流中。
}
}
package SingleThread;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;
public class SingleThreadClient {
public static void main(String[] args) throws IOException {
//1.创建客户端,连接到服务器。
int port=7777;
if(args.length>0){
port=Integer.parseInt(args[0]);
}else{
System.out.println("端口参数不正确,采用默认参数");
}
String host="127.0.0.1";
if(args.length>1){
host=args[1];
}
Socket clientSocket=new Socket(host,port);
//2.接收,发送数据
//2.1发送数据
OutputStream clientOutput=clientSocket.getOutputStream();
OutputStreamWriter writer=new OutputStreamWriter(clientOutput);
writer.write("你好,我是客户端\n");//写到输出流中,服务器端读取到的数据
writer.flush();
//2.2接收数据
InputStream clientInput=clientSocket.getInputStream();
Scanner scanner=new Scanner(clientInput);
String serverData=scanner.nextLine();
System.out.println("来自服务器端的数据:"+serverData);
//3.客户端的关闭
clientOutput.close();
clientInput.close();
clientSocket.close();
}
}
先启动服务器端,结果为:
再启动客户端,结果客户端显示为:
服务器端显示为: