java网络编程之Socket编程
概念
网络编程分为BIO(传统IO)、NIO、AIO。Socket编程属于BIO这种传统IO。
InetAddress
java.net.InetAddress是JAVA中管理IP地址的类,常用

public static void main(String[] args) throws UnknownHostException {
InetAdressDemo.getLocalHost();
System.out.println("---------------------------");
getHostByName("Lenovo-Autumn");
}
/**
* 获取主机ip和主机名
* @throws UnknownHostException
*/
public static void getLocalHost() throws UnknownHostException {
//根据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地址
* @param otherName 主机名(可以是局域网中的机器名或者是域名或者是ip)
* @throws UnknownHostException
*/
public static void getHostByName(String otherName) throws UnknownHostException {
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

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

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

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

返回数据缓冲区

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

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

构造函数:
用来创建发送端的DatagramSocket对象

用来创建接收端的DatagramSocket对象

方法:
发送数据报包

接收数据报包

发送端
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 class UdpSend {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
//获取地址
InetAddress inet = InetAddress.getByName("127.0.0.1");
//创建DatagramSocket,负责接受和发送数据
DatagramSocket ds = new DatagramSocket();
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 class UdpReceive {
public static void main(String[] args) throws IOException {
//创建数据包传输的对象,并绑定端口号
DatagramSocket ds = new DatagramSocket(6000);
//创建字节数组
byte[] data = new byte[1024];
while(true){
//创建数据包对象,传递字节数组
DatagramPacket dp = new DatagramPacket(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类,用于表示客户端。建立连接后用流进行输入和输出

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

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

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

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


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

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

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

返回端口号

客户端
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 class TCPServer {
public static void main(String[] args) throws IOException {
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 class TCPClient {
public static void main(String[] args) throws IOException {
//创建Socket对象,连接服务器
Socket socket = new Socket("127.0.0.1",8888);
//通过客户端的套接字对象Socket方法,获取字节输出流,将数据写向服务器
OutputStream out = socket.getOutputStream();
out.write("这是一条来客户端的数据".getBytes());
socket.close();
}
}
用cmd命令telnet实现和SocketServer互动
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket; public class TCPServer {
/*同步阻塞*/
public static void main(String[] args) throws IOException {
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("服务器端关闭....");
}
}
连接服务端

向服务端发送数据

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

线程池改进,能并发访问
用ExecutorService线程池实现每一个连接创建一个新的线程
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class TCPServer {
/*异步阻塞*/
public static void main(String[] args) throws IOException {
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 void run() {
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)
java网络编程之Socket编程的更多相关文章
- java 网络编程之Socket编程
1.客户端代码 1 package com.gylhaut.socket; 2 3 import java.io.BufferedReader; 4 import java.io.IOExcept ...
- java网络编程之socket
网络编程是什么 网络编程的本质是两个设备之间的数据交换,当然,在计算机网络中,设备主要指计算机.数据传递本身没有多大的难度,不就是把一个设备中的数据发送给两外一个设备,然后接受另外一个设备反馈的数据. ...
- java网络编程之socket(1)
网络编程是什么 网络编程的本质是两个设备之间的数据交换,当然,在计算机网络中,设备主要指计算机.数据传递本身没有多大的难度,不就是把一个设备中的数据发送给两外一个设备,然后接受另外一个设备反馈的数据. ...
- linux网络编程之socket编程(一)
今天开始,继续来学习linux编程,这次主要是研究下linux下的网络编程,而网络编程中最基本的需从socket编程开始,下面正式开始学习: 什么是socket: 在学习套接口之前,先要回顾一下Tcp ...
- linux网络编程之socket编程(八)
学习socket编程继续,今天要学习的内容如下: 先来简单介绍一下这五种模型分别是哪些,偏理论,有个大致的印象就成,做个对比,因为最终只会研究一个I/O模型,也是经常会用到的, 阻塞I/O: 先用一个 ...
- linux网络编程之socket编程(三)
今天继续对socket编程进行学习,在学习之前,需要回顾一下上一篇中编写的回射客户/服务器程序(http://www.cnblogs.com/webor2006/p/3923254.html),因为今 ...
- linux网络编程之socket编程(二)
今天继续对socket编程进行研究,这里会真正开如用socket写一个小例子,进入正题: TCP客户/服务器模型: 关于这个模型的流程这里就不多说了,比较容易理解,下面则利用这种模型来编写一个实际 ...
- linux网络编程之socket编程(十二)
今天继续学习socket编程,期待的APEC会议终于在京召开了,听说昨晚鸟巢那灯火通明,遍地礼花,有点08年奥运会的架势,有种冲动想去瞅见一下习大大的真容,"伟大的祖国,我爱你~~~&quo ...
- linux网络编程之socket编程(十一)
今天继续学习socket编程,这次主要是学习超时方法的封装,内容如下: ①.alarm[不常用,了解既可] 它的实现思路是这样的: 但是这种方案有一定的问题,因为闹钟可能会作为其它的用途,这时所设置的 ...
随机推荐
- Jenkins中maven的作用--构建项目(三)
本文主要根据Jenkins上的日志来继续说明构建项目的过程,上文我们已经讲到构建一个测试环境或单独终端的过程,详情可以了解上篇文章 一.背景介绍 首先看下SVN代码的仓库的结构: 代码仓库里有一个文件 ...
- SVN创建主干,分支、合并分支
1.创建主干(trunk) 本文承接上文部分内容:http://www.cnblogs.com/dadonggg/p/8383696.html:部分不明,可以访问这篇文章. 当我们创建完代码仓库后,创 ...
- angular $http服务详解
它是对原生XMLHttpRequest对象的简单封装, 这个方法会返回一个promise对象,具有sccess和error两个方法. 当然,我们也可以在响应返回时用then 方法来处理,会得到一个特殊 ...
- 001-ant design安装及快速入门【基于纯antd的基本项目搭建】
一.安装使用 1.1.安装 推荐使用 npm 或 yarn 的方式进行开发 npm install antd --save yarn add antd 1.2.浏览器引入 在浏览器中使用 script ...
- SpringBoot 集成Spring security
Spring security作为一种安全框架,使用简单,能够很轻松的集成到springboot项目中,下面讲一下如何在SpringBoot中集成Spring Security.使用gradle项目管 ...
- Nginx 403 forbidden原因及故障模拟重现(转载)
这篇文章是转载过来的一篇文章,觉得不错,因此做个记录. 访问Nginx出现状态码为403 forbidden原因及故障模拟 1) nginx配置文件里不配置默认首页参数或者首页文件在站点目录下没有 i ...
- (android实战)破解apk
简单的总结几个关键步骤: 一.工具准备:apktool , dex2jar , jd-gui 二.使用dex2jar + jd-gui 得到apk的java源码 1.用解压工具从 apk包中取出 cl ...
- [华为]查找两个字符串a,b中的最长公共子
链接:https://www.nowcoder.com/questionTerminal/181a1a71c7574266ad07f9739f791506来源:牛客网 查找两个字符串a,b中的最长公共 ...
- jdk eclipse SDK下载安装及配置教程
原文地址https://blog.csdn.net/dr_neo/article/details/49870587 最新鲜最详细的Android SDK下载安装及配置教程 最近Neo突发神经,想要将学 ...
- docker——核心实现技术
作为一种容器虚拟化技术,Docker深度应用了操作系统的多项底层支持技术. 早期版本的Docker是基于已经成熟的Linux Container(LXC)技术实现的.自从0.9版本起,Docker逐渐 ...