客户端(发送端)
1.创建客户端的Socket对象:
参数需要传递要服务端(接收端)的IP和端口,会去链接服务端,服务端连接不上代码会报错
Socket socket =new Socket("127.0.0.1",10000);
2.从Socket对象中获取输出流,写出数据
OutputStream os = socket.getOutputStream();//获取字节流 os.write("邓子AND诩子".getBytes());//写入数据
3.释放资源
socket.close();
服务端(接收端)
1.创建ServerSocket对象
连接不上端口会报错
ServerSocket ss=new ServerSocket(10000);//绑定一个接收端的端口,需要跟发送端保持一致
2.监听客户端的链接:等待客户端的链接,连接成功返回客户端的Socket对象,没连接则一直等待
Socket socket=ss.accept();
3.从连接通道中获取输入流读取数据
InputStream is=socket.getInputStream();
注意:获取到的是字节流,如果传输中文,可能出现乱码问题,将字节流进行包装成高级流即可,详情可看我之前的IO流文章。
4.释放资源
socket.close();//断开跟客户端的连接 ss.clode();//关闭服务器
细节:
1.运行代码要先运行服务端,所以客户端创建Socket对象时,连接就建立
3.Socket可以看成一个通道,输入输出流是在通道中建立的。通道关闭,流自动关闭。
客户端和服务端通过三次握手和四次挥手两个协议保证连接成功和断开
1.三次握手:保证连接的建立
1.客户端向服务端发出连接请求,等待服务器确认
2.服务器返回客户端一个响应,告诉客户端收到了请求
3.客户端向服务端再次发出确认消息,连接成功建立
2.四次挥手:确保连接断开确保连接断开且数据处理完毕
1.客户端向服务端发出取消连接请求
2.服务器向客户端返回一个响应,表示收到客户端请求
3.服务器将通道内数据处理完毕,再次向客户端发出确认取消信息
4.客户端再次发送确认信息,连接断开。
下面用几个小测试来讲解一些Java实现代码的小细节
test1:多发多收
public class Cllient { public static void main(String[] args) throws IOException { Scanner sc=new Scanner(System.in); Socket socket = new Socket("127.0.0.1",10001); OutputStream os = socket.getOutputStream(); while(true) { System.out.println("请输入您要发送的消息"); String str=sc.nextLine(); os.write((str+"\n").getBytes()); if("886".equals(str)){ break; } } os.close(); socket.close(); } }
public class Server { public static void main(String[] args) throws IOException { ServerSocket ss= new ServerSocket(10001); Socket socket = ss.accept(); InputStream is = socket.getInputStream(); InputStreamReader isr=new InputStreamReader(is); int ch; while((ch= isr.read())!=-1) { System.out.print((char)ch); } socket.close(); ss.close(); } }
细节:我们可以看到客户端进行了循环发送,但是服务端没有循环接收,这是因为客户端未完成循环无法发送关闭连接请求,服务端read方法一直在连接通道读取数据,四次挥手无法完成,连接通道无法关闭。
test2:接收反馈
public class Clinet { public static void main(String[] args) throws IOException { Socket socket=new Socket("127.0.0.1",10001); OutputStream os=socket.getOutputStream(); os.write("邓子AND诩子".getBytes()); socket.shutdownOutput(); InputStream is = socket.getInputStream(); InputStreamReader isr=new InputStreamReader(is); int ch; while((ch=isr.read())!=-1){ System.out.println((char)ch); } socket.close(); } }
public class Server { public static void main(String[] args) throws IOException { ServerSocket sc=new ServerSocket(10001); Socket socket = sc.accept(); InputStream is = socket.getInputStream(); InputStreamReader isr=new InputStreamReader(is); int ch; while((ch=isr.read())!=-1){ System.out.println((char)ch); } OutputStream os= socket.getOutputStream(); os.write("诩子AND邓子".getBytes()); socket.close(); sc.close(); } }
细节:我们通过建立socket通道后双方能够进行获取流进行互相发送消息,当客服端的消息发送完成后调用了socket.shutdownOutputStream方法,是一个结束标记告诉服务端此次接收已经完成,使服务端程序跳出read方法。
test3:多线程版的服务端
public class Client { public static void main(String[] args) throws IOException { Scanner sc=new Scanner(System.in); Socket socket = new Socket("127.0.0.1",10001); OutputStream os = socket.getOutputStream(); while(true) { System.out.println("请输入您要发送的消息"); String str=sc.nextLine(); os.write((str+"\n").getBytes()); if("886".equals(str)){ break; } } os.close(); socket.close(); } }
public class Server { public static void main(String[] args) throws IOException { ServerSocket ss= new ServerSocket(10001); while(true){ Socket socket = ss.accept(); new MyThread(socket).start(); } } }
public class MyThread extends Thread { Socket socket; MyThread(Socket socket){ this.socket=socket; } @Override public void run() { try { InputStream is = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(is); int ch; while ((ch = isr.read()) != -1) { System.out.print((char) ch); } } catch (IOException e) { throw new RuntimeException(e); } finally { try { socket.close(); } catch (IOException e) { throw new RuntimeException(e); } } } }
细节:一个ServerSocket对象可以接收多个socket对象,因此采用多线程的方式可以实现多人同时给服务端发送数据。