Socket通信
来源:互联网 发布:c语言四种基本数据类型 编辑:程序博客网 时间:2024/06/06 16:26
一、端口、IP、Socket
总体来说端口和IP共同组成了Socket
二、Java中与网络相关的类
1、InetAddress类
InetAddress类的对象用于IP地址和域名等
public class InetAddressDemo1{ public static void main(String[] args) throws UnknownHostException { /*直接获取本机的InetAddress实例,InetAddress的实例由IP地址和可能的对应主机名组成*/ InetAddress address = InetAddress.getLocalHost(); System.out.println("本机名称:"+address.getHostName()); System.out.println("本机IP地址:"+address.getHostAddress()); byte[] bytes=address.getAddress();//获取字节数组形式的IP地址 System.out.println("字节数组形式的IP地址:"+Arrays.toString(bytes)); System.out.println(address); /*根据机器名获取InetAddress实例;根据IP地址获取InetAddress实例*/ InetAddress address2=InetAddress.getByName("LAPTOP-0QPS2MS9"); System.out.println("计算机名称:"+address2.getHostName()); System.out.println("计算机IP地址:"+address2.getHostAddress()); InetAddress address3=InetAddress.getByName("10.70.58.237"); System.out.println("计算机名称:"+address3.getHostName()); System.out.println("计算机IP地址:"+address3.getHostAddress()); }}
程序运行结果:
本机名称:LAPTOP-0QPS2MS9
本机IP地址:172.20.10.2
字节数组形式的IP地址:[-84, 20, 10, 2]
LAPTOP-0QPS2MS9/172.20.10.2
计算机名称:LAPTOP-0QPS2MS9
计算机IP地址:172.20.10.2
计算机名称:windows10.microdone.cn
计算机IP地址:10.70.58.237
2、URL类
/* * URL常用方法 */public class URLDemo{ public static void main(String[] args) { try { //创建一个URL实例 URL imooc=new URL("https://www.imooc.com"); //在已经创建的url的基础上创建一个新的url //?后面表示参数,#后面表示锚点 URL url=new URL(imooc, "/index.html?username=tom#test"); //获取url协议名、主机名、端口号 System.out.println("协议:"+url.getProtocol()); System.out.println("主机地址:"+url.getHost()); //由于创建url协议的时候没有指定端口号,因此使用默认端口号80,但是返回值为-1 System.out.println("端口号:"+url.getPort()); System.out.println("文件路径:"+url.getPath()); System.out.println("文件名:"+url.getFile()); System.out.println("相对路径:"+url.getRef()); System.out.println("查询字符串:"+url.getQuery()); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
程序运行结果
协议:https
主机地址:www.imooc.com
端口号:-1
文件路径:/index.html
文件名:/index.html?username=tom
相对路径:test
查询字符串:username=tom
/* * 使用URL读取网页内容 */public class URLDemo2{ public static void main(String[] args) { try { //创建一个URL实例 URL url=new URL("https://www.baidu.com"); //通过URL的openStream方法获取URL对象所表示的资源的字节输入流 InputStream is=url.openStream(); //将字节输入流转换为字符输入流,指定GBK编码 InputStreamReader isr=new InputStreamReader(is,"utf-8"); //为字符输入流添加缓冲,提高读取效率 BufferedReader br=new BufferedReader(isr); String data=br.readLine();//一次读取一行数据 while(data!=null)//只要没读完就继续读下一行 { System.out.println(data); data=br.readLine(); } br.close(); isr.close(); is.close(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }}
程序运行结果
<!DOCTYPE html><!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus=autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn" autofocus></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=https://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>'); </script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>©2017 Baidu <a href=http://www.baidu.com/duty/>使用百度前必读</a> <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a> 京ICP证030173号 <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
三、Socket通信及实现步骤
1、基于TCP的Socket通信
ServerSocket 一般仅用于设置端口号和监听,真正进行通信的是服务器端的Socket与客户端的Socket,在ServerSocket 进行accept之后,就将主动权转让了。
/* * 实现基于TCP协议的Socket通信,实现用户登录 * 服务器端 */public class Server{ public static void main(String[] args) { try { //1、创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口 ServerSocket serverSocket=new ServerSocket(8888); //2、调用accpet()方法开始监听,等待客户端连接,同时accept方法会返回一个Socket对象用来与客户端进行通信 Listens for a connection to be made to this socket and accepts it. System.out.println("服务器即将启动,等待客户端连接"); Socket socket=serverSocket.accept(); //3、获取输入流,用来读取客户端发送的信息 InputStream is=socket.getInputStream();//字节输入流 InputStreamReader isr=new InputStreamReader(is);//将字节流包装为字符流用来提升读取性能 BufferedReader br=new BufferedReader(isr);//为输入流添加缓冲 String info=null; //循环读取客户端的信息 while((info=br.readLine())!=null) { System.out.println("我是服务器,客户端说:"+info); } //获取输出流,响应客户端请求 OutputStream os=socket.getOutputStream(); PrintWriter pw=new PrintWriter(os);//将输出流包装成打印流 pw.write("欢迎您!"); pw.flush();//调用flush方法将缓冲输出给客户端 //关闭输入流 socket.shutdownInput(); //关闭资源 br.close(); isr.close(); is.close(); socket.close(); serverSocket.close(); pw.close(); os.close(); } catch (IOException e) { e.printStackTrace(); } }}
/* * 客户端 */public class Client{ public static void main(String[] args) { try { //1、创建客户端Socket,指定服务器地址和端口,由于这个案例中服务器和客户端在同一台主机上,因此用的是同一个ip地址,localhost表示的就本机地址 Socket socket=new Socket("localhost", 8888); //2.获取输出流,向服务器发送登陆信息 OutputStream os=socket.getOutputStream(); PrintWriter pw=new PrintWriter(os);//将输出流包装为打印流 pw.write("用户名:admin;密码:123"); pw.flush(); socket.shutdownOutput();//关闭输出流,一定要写在使用输出流的语句前面! //获取输入流,用来读取服务器相应的信息 InputStream is=socket.getInputStream(); BufferedReader br=new BufferedReader(new InputStreamReader(is)); String info=null; while((info=br.readLine())!=null) { System.out.println("我是客户端,服务器说:"+info); } pw.close(); os.close(); is.close(); br.close(); socket.close(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }}
在执行程序的时候要注意步骤,必须先启动服务器再启动客户端。
程序运行结果
首先启动服务器,显示如下
服务器即将启动,等待客户端连接
然后启动客户端,服务器显示如下
服务器即将启动,等待客户端连接我是服务器,客户端说:用户名:admin;密码:123
客户端显示如下
我是客户端,服务器说:欢迎您!
但实际上在编写这个程序的过程中我遇上了一些问题,在编写客户端的时候,socket.shutdownOutput
原来是放在读取服务器发送的信息并相应的功能之后的,但是这样做的结果是服务器无法接收到客户端发送的数据,这个疑惑尚待解决。
下面在基于上面的例子上,我们再完成一个利用多线程实现一台服务器与多个客户端通信的Demo。要想让一台服务器与多个客户端进行响应,那我们就需要创建一个线程类,在线程中完成服务器与客户端的通信,而不是直接在服务器类中完成通信。
/* * 服务器线程处理类,在线程中完成服务器与客户端的通信 */public class ServerThread extends Thread{ //和本线程相关的Socket Socket socket=null; //构造方法,为Socket赋值 public ServerThread(Socket socket) { this.socket=socket; } //线程执行的操作,响应客户端的请求 @Override public void run() { super.run(); InputStream is=null; InputStreamReader isr=null; BufferedReader br=null; OutputStream os=null; PrintWriter pw=null; try { //获取输入流,用来读取客户端发送的信息 is = socket.getInputStream(); isr=new InputStreamReader(is);//将字节流包装为字符流用来提升读取性能 br=new BufferedReader(isr);//为输入流添加缓冲 String info=null; //循环读取客户端的信息 while((info=br.readLine())!=null) { System.out.println("我是服务器,客户端说:"+info); } //获取输出流,响应客户端请求 os=socket.getOutputStream(); pw=new PrintWriter(os);//将输出流包装成打印流 pw.write("欢迎您!"); pw.flush();//调用flush方法将缓冲输出 } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { try { //关闭输入流 socket.shutdownInput(); //关闭资源 br.close(); isr.close(); is.close(); pw.close(); os.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } }}
/* * 实现基于TCP协议的Socket通信,实现用户登录 * 服务器端 */public class Server{ public static void main(String[] args) { try { //1、创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口,服务器的IP就是本机IP地址 ServerSocket serverSocket=new ServerSocket(8888); Socket socket=null; //记录连接的客户端的数量 int count=0; System.out.println("服务器即将启动,等待客户端连接"); //循环监听等待客户端的连接,利用多线程以实现一个服务器与多个客户端通信 while(true) { //2、调用accpet()方法开始监听,等待客户端连接 socket=serverSocket.accept(); //客户端与服务器连接后就创建一个新的线程,在线程里完成两者之间的通信操作 ServerThread serverThread=new ServerThread(socket); //启动线程 serverThread.start(); //统计客户端的数量 count++; System.out.println("客户端的数量为:"+count); //获取客户端的IP地址 InetAddress address=socket.getInetAddress(); System.out.println("当前客户端的IP:"+address.getHostAddress()); } } catch (IOException e) { e.printStackTrace(); } }}
/* * 客户端 */public class Client{ public static void main(String[] args) { try { //1、创建客户端Socket,指定服务器IP地址和端口,由于这个案例中服务器和客户端在同一台主机上,因此用的是同一个ip地址,localhost表示的就本机地址 Socket socket=new Socket("localhost", 8888);//执行了这条语句后,客户端就已经与服务器产生了连接。 //2.获取输出流,向服务器发送登陆信息 OutputStream os=socket.getOutputStream(); PrintWriter pw=new PrintWriter(os);//将输出流包装为打印流 pw.write("用户名:admin;密码:123"); pw.flush(); socket.shutdownOutput();//关闭输出流,一定要写在使用输出流的语句前面! //获取输入流,用来读取服务器相应的信息 InputStream is=socket.getInputStream(); BufferedReader br=new BufferedReader(new InputStreamReader(is)); String info=null; while((info=br.readLine())!=null) { System.out.println("我是客户端,服务器说:"+info); } pw.close(); os.close(); is.close(); br.close(); socket.close(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }}
这样我们就完成了一个服务器与多个客户端同时通信的例子,下面运行代码。
先启动服务器:
服务器即将启动,等待客户端连接
再启动第一个客户端,则客户端显示
我是客户端,服务器说:欢迎您!
这时服务器端显示
服务器即将启动,等待客户端连接客户端的数量为:1当前客户端的IP:127.0.0.1我是服务器,客户端说:用户名:admin;密码:123
再启动第二个客户端,则客户端显示
我是客户端,服务器说:欢迎您!
这时服务器端显示
服务器即将启动,等待客户端连接客户端的数量为:1当前客户端的IP:127.0.0.1我是服务器,客户端说:用户名:admin;密码:123客户端的数量为:2当前客户端的IP:127.0.0.1我是服务器,客户端说:用户名:admin;密码:123
由此可见我们已经实现了两个客户端与一个服务器进行通信。
2、基于UDP的Socket通信
需要注意的是在基于UDP的Socket通信机制中,Socket类不再用来指定目标(如客户端、服务器),取而代之的DatagramPacket,DatagramPacket不仅仅用来打包发送的数据,还起到了接收数据和指定目标的作用,而Socket只起到了发送DatagramPacket和接收DatagramPacket的作用。
/*服务器端*/public class Server{ public static void main(String[] args) throws IOException { /* * 接收客户端的数据 */ //创建服务器端DatagramSocket,并指定端口号 DatagramSocket socket=new DatagramSocket(8802); //创建DatagramPacket,用于接收客户端发送的数据,并存放在字节数组当中 byte[] bytes=new byte[1024]; DatagramPacket packet=new DatagramPacket(bytes, bytes.length); //等待接收客户端发送的数据.在未接收到数据前处于阻塞状态 System.out.println("服务器已启动,等待客户端发送数据"); socket.receive(packet); //接收到客户端发送的数据后读取之 String info=new String(bytes, 0, packet.getLength()); System.out.println("我是服务器,客户端说:"+info); /* * 响应客户端 */ InetAddress address=packet.getAddress();//获取客户端的地址 int port=packet.getPort();//获取端口 byte[] bytes2="欢迎登陆!".getBytes();//将响应给客户端的数据内容存放在字节数组中 DatagramPacket packet2=new DatagramPacket(bytes2, bytes2.length, address, port); socket.send(packet2); //关闭资源 socket.close(); }}
/*客户端*/public class Client{ public static void main(String[] args) throws IOException { /* * 向服务器端发送数据 */ //定义要通信的服务器的地址、端口号、数据 InetAddress address=InetAddress.getByName("localhost"); int port=8802; byte[] bytes="用户名:admin;密码:123".getBytes();//将要发送的数据存放在字节数组中 //创建数据报,包含发送的数据信息:如数据内容、数据长度、发送到的服务器信息(地址和端口号) DatagramPacket packet=new DatagramPacket(bytes, bytes.length, address, port); //创建DatagramSocket来发送数据报 DatagramSocket socket=new DatagramSocket(); //发送数据报 socket.send(packet); /* * 接收服务器端发送的数据 */ //创建数据报,用于接收服务器端发送的数据 byte[] bytes2=new byte[1024]; DatagramPacket packet2=new DatagramPacket(bytes2, bytes2.length); //用socket接收,读取服务器返回的数据 socket.receive(packet2); String info=new String(bytes2); System.out.println("我是客户端,服务器说:"+info); //关闭资源 socket.close(); }}
- Socket通信
- Socket通信
- socket通信
- Socket通信
- Socket通信
- socket通信
- socket通信
- socket通信
- socket 通信
- socket通信
- SOCKET通信
- Socket通信
- 通信 socket
- socket 通信
- socket通信
- socket通信
- socket通信
- socket通信
- 安装hue-3.11.0并迁移数据库至postgresql
- 字节流转换成字符流的方式和流输入的时候另一种加入换行方式
- 蓝桥杯 警察智力训练(DFS)
- 【Java学习笔记】equals方法和==
- 剑英陪你玩转图形学 (三)归去来
- Socket通信
- instance “error” 了怎么办?- 每天5分钟玩转 OpenStack(159)
- python-字符串反转
- jQuery总结
- html5(h5)和css3(c3)绘制的太阳系
- My “Hello World” For Blog
- fzuacm 2017 新生寒假训练 6
- Leetcode #387 First Unique Character in a String
- OOM