java socket telnet_java网络编程之Socket编程

概念

网络编程分为BIO(传统IO)、NIO、AIO。Socket编程属于BIO这种传统IO。

InetAddress

java.net.InetAddress是JAVA中管理IP地址的类,常用

7fec210991fbf859aff13ecb253449c7.png

public static void main(String[] args) throwsUnknownHostException {

InetAdressDemo.getLocalHost();

System.out.println("---------------------------");

getHostByName("Lenovo-Autumn");

}/*** 获取主机ip和主机名

*@throwsUnknownHostException*/

public static void getLocalHost() throwsUnknownHostException {//根据InetAddress获取主机名和主机ip

InetAddress localHost =InetAddress.getLocalHost();

System.out.println(localHost);//打印:Lenovo-Autumn/192.168.56.1//根据getLocalHost()返回的值获取ip和主机名

String hostName =localHost.getHostName();

String hostAddress=localHost.getHostAddress();

System.out.println(hostName);//打印 Lenovo-Autumn

System.out.println(hostAddress); //打印 192.168.56.1//根据切割获取主机名和ip

String[] str = localHost.toString().split("/");

System.out.println(str[0]); //打印 Lenovo-Autumn

System.out.println(str[1]); //打印 192.168.56.1

}/*** 根据主机名称获取ip地址

*@paramotherName 主机名(可以是局域网中的机器名或者是域名或者是ip)

*@throwsUnknownHostException*/

public static void getHostByName(String otherName) throwsUnknownHostException {

InetAddress otherHost=InetAddress.getByName(otherName);

String hostName=otherHost.getHostName();

String hostAddress=otherHost.getHostAddress();

System.out.println(hostName);//打印 Lenovo-Autumn

System.out.println(hostAddress); //打印 192.168.56.1

System.out.println(otherHost); //打印:Lenovo-Autumn/192.168.56.1

}

UDP

发送数据时必须指定接收端的IP地址和端口号,就好像发送货物的集装箱上面必须标明接收人的地址一样。

接收端不需要明确知道数据的来源,只需要接收到数据即可。

java.net.DatagramPackage

f0b39cc9072adefea0848ec32279871b.png

构造函数:

第一种是用来接受的数据包,不需要指定IP和端口,第二种是用来发送的数据包需要指定ip和端口

6d09e3ead72259eb4c4b6ee543ff7f94.png

方法:

获取ip地址,获取服务器ip或者客户端ip

5220c5ca681c4a3383ab1f2900f6d550.png

返回端口号,获取发送方或者

d7a7f537bff650ebab52dbbb00fb720a.png

返回数据缓冲区

f8629984e235f2e933b3ba13a6c37931.png

返回要发送或接受的数据包大小

6a76841fdee6429d8f8417cabbb244d1.png

java.net.DatagramSocket

DatagramPacket数据包的作用就如同是“集装箱”,可以将发送端或者接收端的数据封装起来。然而运输货物只有“集装箱”是不够的,还需要有码头。在程序中需要实现通信只有DatagramPacket数据包也同样不行,为此JDK中提供的一个DatagramSocket类。DatagramSocket类的作用就类似于码头,使用这个类的实例对象就可以发送和接收DatagramPacket数据包,发送数据的过程如下图所示。

1e2063b8ca457bb1f1e90d58ba7cd888.png

构造函数:

用来创建发送端的DatagramSocket对象

8ba066f03b01426086e4fcb9f15560e1.png

用来创建接收端的DatagramSocket对象

73b3689e7cb0e7385c4eeb0f4995137e.png

方法:

发送数据报包

8c7b2aa5e10b6368aa321b89500a195b.png

接收数据报包

825b7ae93ab50cdd807feb2f9324605f.png

发送端

1,  创建DatagramSocket对象

DatagramSocket()

2,创建DatagramPacket对象,封装数据,并指定ip和端口。

DatagramPacket(byte[] buf, int length, InetAddress address, int port)

3,发送数据

socket.send(DatagramPacket dp)

4,释放流资源

ds.close();

接收端

1,创建DatagramSocket对象,只需要指定端口

DatagramSocket(port)

2,创建DatagramPacket对象

DatagramPacket(byte[] data, int length)

3,接收数据存储到DatagramPacket对象中

receive(DatagramPackage dp)

4,获取DatagramPacket对象的内容

new String(data,0,dp.getLength());

5,释放流资源

ds.close();

/*** 实现udp发送端

* 用java.net.DatagramPackage封装数据

* 用java.net.DatagramSocket发送数据

*

* 实现步骤

* 1.用DatagramPackage对象,封装数据,接受的地址和端口

* 2.创建DatagramSocket

* 3.调用DatagramSocket对象send方法,发送数据

* 4.关闭资源

*

* DatagramPackage构造函数

* DatagramPacket(byte[] buf, int length, InetAddress address, int port)

* DatagramSocket构造函数

* DatagramSocket()

* 方法:send(DatagramPacket d)

* Created by Autumn on 2018/2/5.*/

public classUdpSend {public static void main(String[] args) throwsException {

Scanner scanner= newScanner(System.in);//获取地址

InetAddress inet = InetAddress.getByName("127.0.0.1");//创建DatagramSocket,负责接受和发送数据

DatagramSocket ds = newDatagramSocket();while(true){

String msg=scanner.nextLine();//创建数据包对象对象

byte[] data =msg.getBytes();//封装数据,接受的地址和端口

DatagramPacket dp = new DatagramPacket(data,data.length,inet,6000);//发送数据包

ds.send(dp);if(msg.equals("exit")){break;

}

}//关闭

ds.close();

}

}/*** 实现udp接收端

* 用java.net.DatagramPackage 接受数据

* 用java.net.DatagramSocket 接受数据包

*

* 步骤

* 1.创建DatagramSocket对象,绑定端口号(要和发送端端口一致)

* 2.创建字节数组用来接受数据

* 3.创建数据对象包DatagramPackage

* 4.创建DatagramSocket

* receive(DatagramPackage dp)接受数据,将数据封装如dp中

* 5.拆包

* 发送端的ip地址(DatagramPackage.get)

* 接受到的字节数组

* 发送的端口号

* 6.关闭资源

* Created by Autumn on 2018/2/5.*/

public classUdpReceive {public static void main(String[] args) throwsIOException {//创建数据包传输的对象,并绑定端口号

DatagramSocket ds = new DatagramSocket(6000);//创建字节数组

byte[] data = new byte[1024];while(true){//创建数据包对象,传递字节数组

DatagramPacket dp = newDatagramPacket(data,data.length);//调用ds对象的receive接受数据包,receive()有线程阻塞效果会一直等待接受数据

ds.receive(dp);//获取数据包大小

int len =dp.getLength();//获取发送端的ip地址

InetAddress sendAddress =dp.getAddress();

String sendHostAddress=sendAddress.getHostAddress();//System.out.println(sendHostAddress);//获取发送端端口号

int port =dp.getPort();//System.out.println(port);//System.out.println(new String(data));//直接打印1024个字节的字符串,有很多空格

System.out.println(sendHostAddress+":"+port+" "+new String(data,0,len)); //这样打印没有多余的空格

if(new String(data,0,len).equals("exit")){break;

}

}//关闭

ds.close();

}

}

TCP

ServerSocket类,用于表示服务器端,Socket类,用于表示客户端。建立连接后用流进行输入和输出

47d7243b46658d753c93fb6353c07cd5.png

ServerSocket

实例化一个ServerSocket类,指定端口号

4353761506a954b7cf7b7004229f4886.png

监听并接受此套接字的连接

94d1061528fca889da09744bae295828.png

返回此服务器套接字的本地地址

1d690140c072ad00b326fee2584e3c31.png

Socket

实例化一个Socket并指定ip和端口

e9dcb79ca125afc970529a65c1291787.png

e948839c3ebdc44e9def55f143388b81.png

返回一个输出流,用于客户端发送数据

c4213b125ec5e116b2ac55aa6501b6ee.png

返回一个输入流,用于服务器端接受数据

066a09e7ad1fb4a61fa90a5abbbe8f18.png

返回ip地址(服务器端的地址)

032f985fbee5a9b7bbe7e7ef56cb5d3b.png

返回端口号

6b59b5b4cbc220e4c7968fab1ebf066d.png

客户端

1,创建客户端的Socket对象,指定服务器IP和端口号

Socket(String host, int port)

2,获取Socket的输出流对象

getOutputStream();

3,写数据给服务器

out.write("服务器数据".getBytes());

4,关闭流资源

socket.close();

服务器端

1,创建服务器端ServerSocket对象,指定服务器端端口号

ServerSocket(int port)

2,开启服务器,等待着客户端Socket对象的连接,如有客户端连接,返回客户端的Socket对象

accept()

3,通过客户端的Socket对象,获取客户端的输入流,为了实现获取客户端发来的数据

socket.getInputStream();

4,通过客户端的输入流,获取流中的数据

byte[] data = new byte[1024];

int len = inputStream.read(data);

System.out.println(new String(data,0,len));

5,通过客户端的Socket对象,获取客户端的输出流,为了实现给客户端反馈信息

6,通过客户端的输出流,写数据到流中

7,关闭流资源

socket.close();

serverSocket.close();

/*** 实现TCP服务器程序

* 表示服务器程序的类java.net.ServerSocket

* 构造方法:

* ServerSocket(int port); 传递端口号

*

* Important:必须获得客户端的套接字(Socket)

* 方法:Socket accept()

* 服务器可以获取到客户端的套接字

* Created by Autumn on 2018/2/5.*/

public classTCPServer {public static void main(String[] args) throwsIOException {

ServerSocket serverSocket= new ServerSocket(8888);//调用服务器套接字对象accept()获取客户端套接字,具有线程等待效果

Socket socket =serverSocket.accept(); //这里会阻塞等待连接接入 cmd中telnet 127.0.0.1 8888即可连接//根据获得的客户端的socket获取输入流

InputStream inputStream =socket.getInputStream();//根据输入流将数据读入到data中

byte[] data = new byte[1024];int len =inputStream.read(data); //这里会阻塞,等待数据 cmd中ctrl+]进入到telnet操作模式send value发送数据

System.out.println(new String(data,0,len));

socket.close();

serverSocket.close();

}

}/*** 实现TCP客户端,连接到服务器

* 和服务器实现数据交换

* 实现TCP客户端程序的类 java.net.Socket

*

* 构造方法:

* Socket(String host, int port)传递服务器IP和端口号

* 注意:构造方法只要运行,就会和服务器进行连接,连接时报,抛出异常

*

* OutputStream getOutputStream() 返回套接字的输出流

* 作用:将数据输出,输出到服务器

* InputStream getInputStream() 返回套接字的输入流

* 作用:从服务器端读取数据

*

* 客户端服务器数据交换,必须使用套接字对象Socket中的获取的IO刘,自己new的流不行

*

* Created by Autumn on 2018/2/5.*/

public classTCPClient {public static void main(String[] args) throwsIOException {//创建Socket对象,连接服务器

Socket socket = new Socket("127.0.0.1",8888);//通过客户端的套接字对象Socket方法,获取字节输出流,将数据写向服务器

OutputStream out =socket.getOutputStream();

out.write("这是一条来客户端的数据".getBytes());

socket.close();

}

}

用cmd命令telnet实现和SocketServer互动

importjava.io.IOException;importjava.io.InputStream;importjava.net.ServerSocket;importjava.net.Socket;public classTCPServer {/*同步阻塞*/

public static void main(String[] args) throwsIOException {

ServerSocket serverSocket= new ServerSocket(8888);

System.out.println("服务端启动成功...");while(true){/*一次只能处理一个连接,在一个连接没关闭前无法接收第二个连接,在这里开一个框发送数无问题,开放两个框时会出现第二个无反应*/Socket socket= serverSocket.accept(); //这里会阻塞等待连接接入 cmd中telnet 127.0.0.1 8888即代表连接

System.out.println("新客户端连接成功....");

InputStream inputStream=socket.getInputStream();while(true) {byte[] data = new byte[1024];

System.out.println("正在等待数据...");int len = inputStream.read(data); //这里会阻塞,等待数据,如果直接关闭cmd窗口会因为关闭socket通道导致len返回-1 cmd中ctrl+]进入到telnet操作模式send value发送数据

if (len != -1){

System.out.println(new String(data, 0,len, "GBK")); //用GBK是因为CMD窗口命令发送的数据是GBK编码

}else{break;

}

}

}//socket.close();//serverSocket.close();//System.out.println("服务器端关闭....");

}

}

连接服务端

30b177d1cc5a315a9acf59be7c18b2c3.png

向服务端发送数据

748eaaa0853549cfa9f3adf48f790359.png

再开一个cmd然后telnet发送数据,发现无反应。必须关闭第一个cmd才能连接成功。

8cf16aa06274b1020f5e2647fb63d622.png

线程池改进,能并发访问

用ExecutorService线程池实现每一个连接创建一个新的线程

importjava.io.IOException;importjava.io.InputStream;importjava.io.UnsupportedEncodingException;importjava.net.ServerSocket;importjava.net.Socket;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;public classTCPServer {/*异步阻塞*/

public static void main(String[] args) throwsIOException {

ExecutorService threadPool= Executors.newCachedThreadPool(); //线程池

ServerSocket serverSocket = new ServerSocket(8888);

System.out.println("服务端启动成功...");while(true){/*一次只能处理一个连接,在一个连接没关闭前无法接收第二个连接,在这里开一个框发送数无问题,开放两个框时会出现第二个无反应*/System.out.println("等待客户端连接...");final Socket socket = serverSocket.accept(); //这里会阻塞等待连接接入 cmd中telnet 127.0.0.1 8888即代表连接

threadPool.execute(new Runnable() { //启动一个线程

public voidrun() {try{

System.out.println("新客户端连接成功....");

InputStream inputStream=socket.getInputStream();while(true) {byte[] data = new byte[1024];

System.out.println("正在等待数据...");int len = inputStream.read(data); //这里会阻塞,等待数据,如果直接关闭cmd窗口会因为关闭socket通道导致len返回-1 cmd中ctrl+]进入到telnet操作模式send value发送数据

if (len != -1){

System.out.println(Thread.currentThread()+new String(data, 0,len, "GBK")); //用GBK是因为CMD窗口命令发送的数据是GBK编码

}else{

System.out.println("break循环");break;

}

}

System.out.println("一次Socket连接关闭");

}catch(UnsupportedEncodingException e) {

e.printStackTrace();

}catch(IOException e) {

e.printStackTrace();

}

}

});

}//socket.close();//serverSocket.close();//System.out.println("服务器端关闭....");

}

}

优点:传输质量好(所以BIO适合传输连接少但是数据量大的请求)

缺点:每一个连接都占用一个线程,很占用系统资源。

tip:所有的调优都关联到系统资源(IO、存储、内存、CPU)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值