网络通讯Socket
Posted yunianzeng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络通讯Socket相关的知识,希望对你有一定的参考价值。
网络
在物理网络的基础上,建立抽象的连接
win + r, 输入 cmd
输入命令:
ipconfig
如果ping不通,要关闭防火墙
开始---搜索防火墙
Socket 通信
Socket - 插头
Socket - 网络套接字
通过 ip 地址,两台主机可以互相找到对象
在两台主机上,各选择一个端口号
端口是独占的,0到1024是一些常见服务的默认端口---http 80--https 443--ftp 21...5万以后,是系统保留端口用,来自动分配
我们选择端口要选择 1024到5万之间的端口号
服务器端
被动等待客户端发起连接
ServerSocket 在服务器端,选择一个端口号, 在指定端口上等待客户端发起连接
ServerSocket ss = new ServerSocket(8000);
等待客户端发起连接,建立连接通道,并返回连接通道的服务器端插头对象
Socket s = ss.accept();
客户端
主动去连接服务器
Socket s = new Socket(ip, port);
取出双向的流
InputStream in = s.getInputStream(); OutputStream out = s.getOutputStream();
超时
socket.setSoTimeout(毫秒值)
设置接收数据,等待超时时长,超时会出现 SocketTimeoutException
实例:
package demo; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class Server1 { public static void main(String[] args) throws Exception { ServerSocket ss = new ServerSocket(8000); System.out.println( "服务已经在 8000 端口上启动"); //暂停等待客户端发起连接 System.out.println("等待客户端连接"); Socket s = ss.accept(); System.out.println("客户端已连接"); //从插头对象,获取输入流和输出流 InputStream in = s.getInputStream(); OutputStream out = s.getOutputStream(); /* * 通信协议,通信流程,数据格式 * * 服务器端: * 1. 接收 "hello" * 2. 发送 "world" */ for (int i = 0; i < 5; i++) { char c = (char) in.read(); System.out.print(c); } out.write("world".getBytes()); out.flush(); //刷出内存缓存 s.close();//断开连接 ss.close();//停止服务,释放端口 } }
Client
package demo; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; public class Client1 { public static void main(String[] args) throws Exception { Socket s = new Socket("旁边同学ip", 8000); InputStream in = s.getInputStream(); OutputStream out = s.getOutputStream(); /* 客户端: * 1. 发送 "hello" * 2. 接收 "world" */ out.write("hello".getBytes()); out.flush(); //刷出内存缓存 for (int i = 0; i < 5; i++) { char c = (char) in.read(); System.out.print(c); } s.close(); } }
阻塞操作
ss.accept()
暂停,等待客户端发起连接
in.read()
对方不发送数据,暂停,死等数据
服务器端的线程模型
回声
客户端发送到服务器的数据,原封不动的发回客户端
EchoServer
package demo; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class EchoServer { public void launch() { new Thread() { @Override public void run() { try { ServerSocket ss = new ServerSocket(8000); System.out.println("服务已在 8000 端口上启动"); while(true) { System.out.println("等待下一个客户端连接"); Socket s = ss.accept(); System.out.println("客户端已连接"); TongXinThread t = new TongXinThread(s); t.start(); } } catch (Exception e) { System.out.println( "无法在 8000 端口上启动服务,或服务已停止"); } } }.start(); } class TongXinThread extends Thread { Socket s; public TongXinThread(Socket s) { this.s = s; } @Override public void run() { /* * 通信协议,流程和格式 * UTF-8编码的字符串, * 每段字符串末尾添加换行 * * BR--ISR--网络输入流 * PW--OSW--网络输出流 */ try { BufferedReader in = new BufferedReader( new InputStreamReader( s.getInputStream(), "UTF-8")); PrintWriter out = new PrintWriter( new OutputStreamWriter( s.getOutputStream(),"UTF-8")); String line; while((line = in.readLine()) != null) { out.println(line); out.flush(); } //断开 } catch (Exception e) { //断开 } System.out.println("一个客户端端已断开"); } } public static void main(String[] args) { EchoServer s = new EchoServer(); s.launch(); } }
EchoClient
package demo; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.net.Socket; import java.util.Scanner; public class EchoClient { public static void main(String[] args) throws Exception { Socket s = new Socket("找一个人启动服务器", 8000); BufferedReader in = new BufferedReader( new InputStreamReader( s.getInputStream(), "UTF-8")); PrintWriter out = new PrintWriter( new OutputStreamWriter( s.getOutputStream(),"UTF-8")); while(true) { System.out.print("输入:"); String str = new Scanner(System.in).nextLine(); out.println(str); out.flush(); String echo = in.readLine(); System.out.println("回声:"+echo); System.out.println("-----------------"); } } }
ChatServer
package demo; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; public class ChatServer { private ArrayList<TongXinThread> list = new ArrayList<>(); public void launch() { //启动服务线程 new Thread() { @Override public void run() { try { ServerSocket ss = new ServerSocket(8000); System.out.println("聊天室服务器已启动"); while(true) { Socket s = ss.accept(); TongXinThread t = new TongXinThread(s); t.start(); } } catch (Exception e) { System.out.println( "服务无法在 8000 端口上启动,或服务已经停止"); } } }.start(); } class TongXinThread extends Thread { Socket s; BufferedReader in; PrintWriter out; private String name; public TongXinThread(Socket s) { this.s = s; } public void send(String msg) { out.println(msg); out.flush(); } public void sendAll(String msg) { synchronized (list) { for (TongXinThread t : list) { t.send(msg); } } } @Override public void run() { try { //UTF-8, 换行 in = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8")); out = new PrintWriter(new OutputStreamWriter(s.getOutputStream(),"UTF-8")); //接收客户端的昵称 this.name = in.readLine(); //把当前通信线程实例,加入集合 synchronized (list) { list.add(this); } //发送欢迎信息 send("欢迎进入激情聊天室"); //群发上线消息 sendAll(name+"进入了聊天室,在线人数:"+list.size()); String line; while((line = in.readLine()) != null) { sendAll(name+"说:"+line); } //断开 } catch (Exception e) { //断开 } //删除当前通信线程实例 synchronized (list) { list.remove(this); } //群发离线消息 sendAll(name+"离开了聊天室,在线人数:"+list.size()); } } public static void main(String[] args) { ChatServer s = new ChatServer(); s.launch(); } }
ChatClient
package demo; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.Socket; import java.util.LinkedList; import java.util.Scanner; public class ChatClient { private Socket s; private BufferedReader in; private PrintWriter out; private String name; private LinkedList<String> list = new LinkedList<>(); private boolean flag; //开关 public void launch() { try { s = new Socket("192.168.21.61", 8000); in = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8")); out = new PrintWriter(new OutputStreamWriter(s.getOutputStream(),"UTF-8")); //昵称 System.out.print("起一个昵称: "); name = new Scanner(System.in).nextLine(); out.println(name); out.flush(); //接收线程 new Thread() { @Override public void run() { receive(); } }.start(); //输入线程 new Thread() { @Override public void run() { input(); } }.start(); //打印线程 new Thread() { @Override public void run() { print(); } }.start(); } catch (Exception e) { System.out.println("无法连接聊天室服务器"); e.printStackTrace(); } } protected void print() { while(true) { synchronized (list) { while (list.isEmpty() || flag) { try { list.wait(); } catch (InterruptedException e) { } } String msg = list.removeFirst(); System.out.println(msg); } } } protected void input() { System.out.println("按回车输入聊天内容"); while(true) { new Scanner(System.in).nextLine(); flag = true;//打开开关 System.out.print("输入聊天内容:"); String s = new Scanner(System.in).nextLine(); out.println(s); out.flush(); flag = false;//关闭开关 //通知打印线程可以继续打印 synchronized (list) { list.notify(); } } } protected void receive() { try { String line; while((line = in.readLine()) != null) { synchronized (list) { list.add(line); //通知打印线程已经有数据可以打印了 list.notify(); } } } catch (Exception e) { } System.out.println("已经与服务器断开连接"); } public static void main(String[] args) { ChatClient c = new ChatClient(); c.launch(); } }
以上是关于网络通讯Socket的主要内容,如果未能解决你的问题,请参考以下文章
VSCode自定义代码片段14——Vue的axios网络请求封装
VSCode自定义代码片段14——Vue的axios网络请求封装