Socket是一个抽象概念,一个应用程序通过一个Socket来建立一个远程连接,而Socket内部通过TCP/IP协议把数据传输到网络。
┌───────────┐ ┌───────────┐
│Application│ │Application│
├───────────┤ ├───────────┤
│ Socket │ │ Socket │
├───────────┤ ├───────────┤
│ TCP │ │ TCP │
├───────────┤ ┌──────┐ ┌──────┐ ├───────────┤
│ IP │<────>│Router│<─────>│Router│<────>│ IP │
└───────────┘ └──────┘ └──────┘ └───────────┘
一个Socket就是由IP地址和端口号(范围是0~65535)组成,可以把Socket简单理解为IP地址加端口号。端口号总是由操作系统分配,它是一个0~65535之间的数字,其中,小于1024的端口属于特权端口,需要管理员权限,大于1024的端口可以由任意用户的应用程序打开。
使用Socket进行网络编程时,本质上就是两个进程之间的网络通信。其中一个进程必须充当服务器端,它会主动监听某个指定的端口,另一个进程必须充当客户端,它必须主动连接服务器的IP地址和指定端口,如果连接成功,服务器端和客户端就成功地建立了一个TCP连接,双方后续就可以随时发送和接收数据。
因此,当Socket连接成功地在服务器端和客户端之间建立后:
●对服务器端来说,它的Socket是指定的IP地址和指定的端口号;
●对客户端来说,它的Socket是它所在计算机的IP地址和一个由操作系统分配的随机端口号。
下面通过一个案例来熟悉一下TCP网络通信的基本步骤:
案例:采用TCP/IP网络通信协议,实现客户端发送文件给服务器端,服务器端接受信息并发送反馈信息给客户端,客户端接受到反馈信息并显示在控制台。
客户端:
1.创建客户端的socket对象,指明服务器端的IP地址和端口号
2.通过客户端的socket对象创建输出流对象
3.文件的写出操作
4.socket.shutdownOutput();// 结束文件发送
5.接受来自服务器端的反馈
//客户端
public class Client {
public static void main(String[] args) {
try (// 创建客户端的socket对象,指明服务器端的IP地址和端口号
Socket socket = new Socket(InetAddress.getLocalHost(), 8899);
// 通过客户端的socket对象创建输出流对象
OutputStream os = socket.getOutputStream();
// 文件的写出操作
FileInputStream fis = new FileInputStream("E:\\picture\\cat.jpg");) {
byte[] buff = new byte[1024];
int len = -1;
while ((len = fis.read(buff)) != -1) {
os.write(buff, 0, len);
}
socket.shutdownOutput();// 结束文件发送
//接受来自服务器端的反馈
try (BufferedReader br= new BufferedReader(new InputStreamReader(socket.getInputStream()));){
String result = br.readLine();
System.out.println("【客户端】来自服务器端的回复:" + result);
} catch (Exception e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务器端:
1.创建服务器端的serverSocket对象,并指明自己的端口号
2.通过serverSocket对象调用accept方法,接受来自客户端的socket对象
3.通过socket对象创建输入流对象
4.文件的写出操作
5.发送反馈信息
//服务器端
public class Server {
public static void main(String[] args) {
try (// 创建服务器端的serverSocket对象,并指明自己的端口号
ServerSocket serverSocket = new ServerSocket(8899)) {
// 通过serverSocket对象调用accept方法,接受来自客户端的socket对象
Socket socket = serverSocket.accept();
String ip = socket.getInetAddress().getHostAddress();// 获取客户端的IP地址
System.out.println("【服务器】客户端" + ip + "连接成功...");
String name = ip.replaceAll("\\.", "\\-");
// 通过socket对象创建输入流对象
try (InputStream is = socket.getInputStream();
FileOutputStream fos = new FileOutputStream("E:\\photo\\" + name + ".jpg");
// 发送反馈信息
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
) {
// 文件的写出操作
byte[] buff = new byte[1024];
int len = -1;
while ((len = is.read(buff)) != -1) {
fos.write(buff, 0, len);
}
System.out.println("【服务器】成功接受到客户端" + ip + "发送来的文件并保存至本地!");
bw.write("文件接收成功并保存至本地!");
} catch (Exception e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
在完成了以上案例后,相信大家对TCP网络编程已经有了基本的认识,下面我们一起完成一个模拟客户端输入姓名,服务器发回反馈信息:xxx,本期双色球中奖号码为【xxxxxx】x的案例。
**
* 客户端发送信息给服务器端并接受来自服务器端的反馈
*
* @Description
* @author tyq
* @version
* @date 2022-7-14 17:27:34
*
*/
public class Client {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
while (true) {
System.out.print("请输入玩家姓名:");
String name = input.nextLine();
if (name.equals("over")) {
break;
}
try (Socket socket = new Socket("192.168.254.139", 8888);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));) {
// 客户端发送信息给服务器端
bw.write(name);
bw.flush();
socket.shutdownOutput();
// 客户端接受来自服务器端的信息
String info = br.readLine();
System.out.println("【客户端】接受来自服务器端的反馈:"+info);
}
catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("游戏结束!");
}
}
/**
* 服务器端接受来自客户端发送的信息,并给予相应的反馈
* @Description
* @author tyq
* @version
* @date 2022-7-14 17:39:13
*
*/
public class Server {
static Set numberSet=new TreeSet<>();
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(8888)) {
while(true) {
Socket socket = serverSocket.accept();
String ip = socket.getInetAddress().getHostAddress();
System.out.println("【服务器】客户端"+ip+"开始登录...");
try(BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
){
//接受来自客户端发来的信息
String name = br.readLine();
if(name!=null) {
System.out.println("【服务器】客户端"+ip+"发送姓名为【"+name+"】,已生成双色球号码信息请在客户端查看!");
//反馈给客户端相应的信息
//1.产生随机下标:[0,list.size()-1] *[b-a+1]+a
while(numberSet.size()!=6) {
int randNum=(int)(Math.random()*33+1);
numberSet.add(randNum);
}
//2.获取集合中的信息
String listInfo =numberSet.toString()+(int)(Math.random()*16+1);
//3.拼接信息
String result=name+"购买本期双色球的幸运号码:"+listInfo;
//4.反馈信息给客户端
bw.write(result);
//5.清空集合
numberSet.clear();
}else {
String error="【错误提示】未接受到来自客户端"+ip+"发送来的信息,请重新输入...";
bw.write(error);
}
}catch (Exception e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
以上是近期学习的一点收获总结,希望对大家有帮助,如果阅读完本文对你有帮助记得留下你的点赞和关注,谢谢!