网络编程

  网络编程主要用于解决计算机与计算机(手机、平板…)之间的数据传输问题。



1.InetAddress(IP类)

  方法:

方法 描述
getLocalHost() 获取本机的IP地址对象
getByName(“IP或者主机名”) 根据一个IP地址的字符串形式或者是一个主机名生成一个IP地址对象。 (用于获取别人的IP地址对象)
getHostAddress() 返回一个IP地址的字符串表示形式。
getHostName() 返回计算机的主机名。
getAddress() 返回此InetAddress对象的原始 IP 地址

2.端口号

  端口号是没有类描述的。

端口号的范围: 0~65535

从0到1023,系统紧密绑定于一些服务。

1024~65535 我们可以使用

  端口常见报错 java.net.BindException: 端口被占用

  在cmd中查看端口号占用

命令 描述
netstat -ano 查看所有的端口
netstat -ano |findstr “8080” 查看指定的端口
tasklist|findstr “PID” 查看占用端口号的进程

3.网络通讯协议

  每个网络程序都有自己所处理的特定格式数据,如果接收到的数据不符合指定的格式,那么就会被当成垃圾数据丢弃。(加密)

  在java网络通讯是通过Socket(插座)通讯技术实现的,要求通讯的两台器都必须要安装Socket。不同的协议就有不同的插座(Socket)

  1. 服务端开启并监听一个端口,时刻等待着客户端的连接请求

  2. 客户端知道服务端的ip地址和监听端口号,发出请求到服务端

  Socket类方法

构造方法 描述
Socket(InetAddress address, int port) 创建一个流套接字并将其连接到指定 IP 地址的指定端口号
主要方法 描述
getInetAddress() 返回套接字连接的地址
public InputStream getInputStream() 返回此套接字的输入流
public OutputStream getOutputStream() 返回此套接字的输出流
方法 描述
void bind​(SocketAddress bindpoint) 将套接字绑定到本地地址。
void close​() 关闭此套接字。
void connect​(SocketAddress endpoint) 将此套接字连接到服务器。
void connect​(SocketAddress endpoint, int timeout) 将此套接字连接到具有指定超时值的服务器。
SocketChannel getChannel​() 返回与此套接字相关联的唯一的SocketChannel对象(如果有)。
InetAddress getInetAddress​() 返回套接字所连接的地址。
InputStream getInputStream​() 返回此套接字的输入流。
boolean getKeepAlive​() 测试是否启用了 SO_KEEPALIVE 。
InetAddress getLocalAddress​() 获取套接字所绑定的本地地址。
int getLocalPort​() 返回此套接字绑定到的本地端口号。
SocketAddress getLocalSocketAddress​() 返回此套接字绑定到的端点的地址。
boolean getOOBInline​() 测试是否启用了 SO_OOBINLINE 。
T getOption​(SocketOption name) 返回套接字选项的值。
OutputStream getOutputStream​() 返回此套接字的输出流。
int getPort​() 返回此套接字连接到的远程端口号。
int getReceiveBufferSize​() 获取此 Socket的 SO_RCVBUF选项的值,即该平台在此 Socket上输入的缓冲区大小。
SocketAddress getRemoteSocketAddress​() 返回此套接字连接到的端点的地址,如果未连接,则 null 。
boolean getReuseAddress​() 测试是否启用了 SO_REUSEADDR 。
int getSendBufferSize​() 获取此 Socket的 SO_SNDBUF选项的值,即平台在此 Socket上输出使用的缓冲区大小。
int getSoLinger​() 退货设置为 SO_LINGER 。
int getSoTimeout​() 退货设置为SO_TIMEOUT 。 0返回意味着该选项被禁用(即无限超时)。
boolean getTcpNoDelay​() 测试是否启用了 TCP_NODELAY 。
int getTrafficClass​() 在从此Socket发送的数据包的IP头中获取流量类或服务类型
boolean isBound​() 返回套接字的绑定状态。
boolean isClosed​() 返回套接字的关闭状态。
boolean isConnected​() 返回套接字的连接状态。
boolean isInputShutdown​() 返回套接字连接的一半是否关闭。
boolean isOutputShutdown​() 返回套接字连接的写半是否关闭。
void sendUrgentData​(int data) 在套接字上发送一个字节的紧急数据。
void setKeepAlive​(boolean on) 启用/禁用 SO_KEEPALIVE 。
void setOOBInline​(boolean on) 启用/禁用 SO_OOBINLINE (接收TCP紧急数据)默认情况下,此选项被禁用,并且在套接字上接收的TCP紧急数据被静默地丢弃。
Socket setOption​(SocketOption name, T value) 设置套接字选项的值。
void setPerformancePreferences​(int connectionTime, int latency, int bandwidth) 设置此套接字的性能首选项。
void setReceiveBufferSize​(int size) 设置 SO_RCVBUF选项,此规定值 Socket 。
void setReuseAddress​(boolean on) 启用/禁用 SO_REUSEADDR套接字选项。
void setSendBufferSize​(int size) 设置 SO_SNDBUF选项,此规定值 Socket 。
static void setSocketImplFactory​(SocketImplFactory fac) 设置应用程序的客户端套接字实现工厂。
void setSoLinger​(boolean on, int linger) 启用/禁用 SO_LINGER具有指定的逗留时间(以秒为单位)。
void setSoTimeout​(int timeout) 启用/禁用 SO_TIMEOUT与指定的超时,以毫秒为单位。
void setTcpNoDelay​(boolean on) 启用/禁用 TCP_NODELAY (禁用/启用Nagle的算法)。
void setTrafficClass​(int tc) 在从此Socket发送的数据包的IP头中设置流量类或服务类型字节。
void shutdownInput​() 将此套接字的输入流放置在“流的末尾”。
void shutdownOutput​() 禁用此套接字的输出流。
Set<SocketOption<?>> supportedOptions​() 返回此套接字支持的一组套接字选项。
String toString​() 将此套接字转换为 String 。

UPD通讯协议

  UDP通讯协议的特点:

1.将数据极封装为数据包,面向无连接

2.每个数据包大小限制在64K中,有大小限制

3.因为无连接,所以不可靠

4.因为不需要建立连接,所以速度快

5.udp 通讯是不分服务端与客户端的,只分发送端与接收端。

在udp协议中,有一个IP地址称作为广播地址,广播地址就是主机号为255地址。 给广播  IP地址发送消息的时候,在同一个网络段的机器都可以接收到信息。

  UDP协议下的Socket:

方法 描述
DatagramSocket(udp插座服务) 用来发送和接受数据包
DatagramPacket(数据包类) 表示数据包

DatagramPacket(buf, length, address, port)

buf: 发送的数据内容

length : 发送数据内容的大小

address : 发送的目的IP地址对象

port : 端口号

发送端的使用步骤:client

  • 1.建立UDP的服务
    DatagramSocket client= new DatagramSocket();
  • 2.准备数据,把数据封装到数据包中发送
	String data = "这个是要发送的数据";
//创建了一个数据包, 发送端的数据包要带上ip地址与端口号
//注意:传输的都是字节流,转换为字节数组
DatagramPacket packet = new DatagramPacket(data.getBytes(),
data.getBytes().length,InetAddress.getByName("IP或者主机名") , 端口号);
  • 3.发送数据包
     client.send(packet); //使用send发送数据包
  • 4.关闭资源 —实际上就是释放占用的端口号
    client.close();

接收端的使用步骤:server

  • 1.建立UDP的服务 ,并且要监听一个端口。这个端口号需要与client中相同才能建立连接
    DatagramSocket  server= new DatagramSocket(要监听的端口号);
  • 2.准备空的数据包用于存放数据。
    byte[] buf = new byte[1024]; //接收的容器
    DatagramPacket packet= new DatagramPacket(buf,0, buf.length); // 1024
  • 3.接收数据包
    //receive是一个阻塞型的方法,没有接收到数据包之前会一直等待。数据是存储到了byte的字节数组中。
    server.receive(packet);
    System.out.println("接收端接收到的数据:"+ new String(buf,0,packet.getLength()));
    // getLength() 获取数据包存储了几个字节。
  • 4.关闭资源
    socket.close();

UPD通讯Demo
UpdClient.class

 package com.gqz.udp;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress; /**
* 基本流程:发送端
* 1、使用DatagramSocket 指定端口 创建接受端
* 2、准备数据,一定要转成字节数组
* 3、封装成DatagramPacket包裹,需要指定目的地
* 4、发送包裹send (DatagramPacket p)
* byte[] getData()
* getLength()
* 5、释放资源
* @ClassName: UdpClient
* @Description: TODO(这里用一句话描述这个类的作用)
* @author ganquanzhong
* @date 2019年7月12日 下午5:29:02
*/
public class UdpClient {
public static void main(String[] args) throws Exception {
System.out.println("client 发送方启动中......");
// 1、使用DatagramSocket 指定端口 创建接受端
DatagramSocket client = new DatagramSocket(8888);
// 2、准备数据,一定要转成字节数组
String data = "模拟UPD发送数据,请求登录(username ,password)";
byte[] datas = data.getBytes(); //字符串转成字节数组
// 3、封装成DatagramPacket包裹,需要指定目的地本机
DatagramPacket packet = new DatagramPacket(datas, datas.length, new InetSocketAddress("localhost", 9999));
// 4、发送包裹send (DatagramPacket p)
client.send(packet);
// byte[] getData()
// getLength()
// 5、释放资源
client.close();
}
}

UpdServer.class

package com.gqz.udp;

import java.net.DatagramPacket;
import java.net.DatagramSocket; /**
* 基本流程:接收端
* 1、使用DatagramSocket 指定端口 创建接受端
* 2、准备容器 封装成DatagramPacket 包裹
* 3、阻塞式接收包裹 recevice (DatagramPacket p)
* 4、分析数据
* byte[] getData()
* getLength()
* 5、释放资源
*
* @ClassName: UdpServer
* @Description: TODO(这里用一句话描述这个类的作用)
* @author ganquanzhong
* @date 2019年7月12日 下午5:29:02
*/
public class UdpServer {
public static void main(String[] args) throws Exception {
System.out.println("server接收 这里是服务端,接收数据启动中..........");
// 1、使用DatagramSocket 指定端口 创建接受端
DatagramSocket server = new DatagramSocket(9999);
// 2、准备容器 封装成DatagramPacket 包裹
byte[] container =new byte[1024*60];//最大60K
DatagramPacket packet = new DatagramPacket(container, 0,container.length);
// 3、阻塞式接收包裹 recevice (DatagramPacket p)
server.receive(packet); //阻塞式
// 4、分析数据
// byte[] getData()
// getLength()
byte[] datas = packet.getData();
System.out.println(packet.getLength());
System.out.println(packet.getOffset());
System.out.println(packet.getPort());
System.out.println(packet.getAddress());
System.out.println(packet.getSocketAddress()); System.out.println(new String(datas));
// 5、释放资源
server.close();
}
}

TCP通讯协议

  TCP通讯协议特点:

tcp是基于IO流进行数据的传输的,面向连接。(需要转换成字节数组)

tcp进行数据传输的时候是没有大小限制的。

tcp是面向连接,通过三次握手的机制保证数据的完整性。可靠协议。

tcp是面向连接的,所以速度慢。

tcp是区分客户端与服务端的。

  tcp协议下的Socket:

  1. Socket(客户端类)    tcp的客户端一旦启动马上要与服务端进行连接。
  2. ServerSocket(服务端类) 使用在服务器端

public class ServerSocket

  extends Object

    implements Closeable

   这个类实现了服务器套接字。 服务器套接字等待通过网络进入的请求。 它根据该请求执行一些操作,然后可能将结果返回给请求者。

  服务器套接字的实际工作由SocketImpl类的实例执行。 应用程序可以更改创建套接字实现的套接字工厂,以配置自己创建适合本地防火墙的套接字。

ServerSocket服务端使用步骤:

try{
//1.建立Tcp的服务端,打开并且监听一个端口。
ServerSocket server= new ServerSocket(监听的端口号); //ServerSocket服务端套接字
//2. 等待接受客户端的连接产生一个Socket
//accept()接受客户端的连接该方法是一个阻塞型的方法,没有客户端与其连接时会一直等待下去。
Socket client = server.accept();
//获取输入输出流对象
InputStream is = client.getInputStream();
OutputStream os = client.getOutputStream();
//3.1 获取输入流对象,读取客户端发送的内容。
byte[] buf = new byte[1024];
int length = 0;
length = is.read(buf);
System.out.println("服务端接收:"+ new String(buf,0,length));
//3.2 获取socket输出流对象,向客户端发送数据
os.write("客户端你好!".getBytes());
//4.关闭资源
is.close():
os.close();
client.close();
server.close();
} catch (IOException e) {
e.printStackTrace();
}

tcp的客户端使用步骤:

try{
//1.通过IP,端口 建立服务端连接
Socket client = new Socket(InetAddress.getByName("IP或者主机名"),端口号);
//2. 获取到Socket的输入、输出流对象
InputStream is = client.getInputStream();
OutputStream os = client.getOutputStream();
//3.1 利用输出流对象,向服务器写出数据。
os.write("服务端你好!".getBytes());
//3.2 利用输入流对象,读取服务端回送的数据。
byte[] buf = new byte[1024];
int length = is.read(buf);
System.out.println("客户端接收到的数据:"+ new String(buf,0,length));
//4.关闭资源
is.close();
os.close();
client.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

  tcp字符流注意细节:

如果使用BuffrerdReader的readline方法一定要加上\r\n才能把数据写出。

使用字符流一定要调用flush方法数据才会写出。

例:tcp字符流通信

客户端
//获取socket的输出流对象。
OutputStreamWriter socketOut = new OutputStreamWriter(socket.getOutputStream());
//获取socket的输入流对象
BufferedReader socketReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//把数据写出给服务器
socketOut.write(发送给服务器的数据+"\r\n"); //注意加上\r\n
socketOut.flush();
//读取服务端回送的数据
socketReader.readLine();
服务端
//获取到Socket的输入流对象
BufferedReader socketReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//获取到Socket输出流对象
OutputStreamWriter socketOut = new OutputStreamWriter(socket.getOutputStream());
//读取客户端的数据
socketReader.readLine()
//回送给客户端数据
socketOut.write(发给客户端的数据+"\r\n"); //注意加上\r\n
socketOut.flush();

TCP通讯Demo
LoginMultiClient .class

package com.gqz.tcp;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException; /*
* 单向连接
* 创建客户端
* 1、建立面向连接:使用Socket创建客户端 (服务器地址和端口)
* 3、操作:输入输出流操作
* 4、释放资源
*/
public class LoginMultiClient {
public static void main(String[] args) throws UnknownHostException, IOException{
System.out.println("=====client=====");
//使用Socket创建客户端 (服务器地址和端口)
Socket client = new Socket("localhost",8888);
//请求服务器 request
new Request(client).send();
//服务器响应
new Response(client).recevie();
//3、释放资源
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
} /**
*
* @ClassName: Request
* @Description: 请求
* @author ganquanzhong
* @date 2019年7月16日 上午10:56:12
*/
static class Request{
private Socket client;
private BufferedReader console;
private DataOutputStream dos;
private String msg;
public Request(Socket client) {
console = new BufferedReader(new InputStreamReader(System.in));
this.msg = init();
this.client = client;
try {
dos= new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
} private String init() {
try {
System.out.print("用户名:");
String username =console.readLine();
System.out.print("密码:");
String password = console.readLine();
return "username="+username+"&"+"password="+password;
} catch (IOException e) {
e.printStackTrace();
}
return "";
} private void send() {
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} /**
*
* @ClassName: Response
* @Description: 响应
* @author ganquanzhong
* @date 2019年7月16日 上午10:56:27
*/
static class Response{
private Socket client;
private DataInputStream dis; public Response(Socket client) {
this.client=client;
try {
dis = new DataInputStream(client.getInputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} private void recevie() {
String result;
try {
result = dis.readUTF();
System.out.println(result);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

LoginMultiServer.class

package com.gqz.tcp;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket; /*
* 熟悉流程
* 单向连接
* 1、指定端口 使用ServerSocket创建服务器
* 2、阻塞式等待连接accept
* 3、操作:输入输出流操作
* 4、释放资源
*/
public class LoginMultiServer {
public static void main(String[] args) throws IOException {
boolean isRunning = true;
System.out.println("=====server=====");
//1、指定端口号 使用ServerSocket创建服务器
ServerSocket server = new ServerSocket(8888); //2、阻塞式等待连接accept
while(isRunning) {
Socket client = server.accept();//建立连接返回一个socket
System.out.println("一个客户端建立连接!");
new Thread(new Channel(client)).start();
}
server.close(); } //一个channel就是一个管道!
static class Channel implements Runnable{
private Socket client;
//输入流
private DataInputStream dis;
private DataOutputStream dos;
public Channel(Socket client) {
this.client=client;
try {
dis = new DataInputStream(client.getInputStream());
dos = new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
release();
}
} //接收数据
private String recevie() {
String datas = "";
try {
datas = dis.readUTF();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return datas;
} //发送数据
private void send(String msg) {
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
e.printStackTrace();
}
} //释放资源
private void release() {
try {
if (null != dos) {
dos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (null != dis) {
dis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (null != client) {
client.close();
}
} catch (IOException e) {
e.printStackTrace();
}
} @Override
public void run() {
//3、操作 :输入输出流操作
//分析数据
String username ="";
String password ="";
String[] dataArray = recevie().split("&");
for(String info:dataArray) {
String[] userInfo = info.split("=");
if (userInfo[0].equals("username")) {
username=userInfo[1];
}else {
password=userInfo[1];
}
}
//判断
if (username.equals("gqz") && password.equals("admin")) {
send("登录成功,欢迎进入ForFuture系统!!");
}else {
send("用户名或密码错误!!");
}
//4、释放资源
release();
} }
}

基于TCP的简单聊天

服务器端Chat.class

package com.gqz.chat;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.CopyOnWriteArrayList; /**
* 服务端,消息转发
* 多个客户可以正常收发消息
* @ClassName: Chat
* @Description: TODO(这里用一句话描述这个类的作用)
* @author ganquanzhong
* @date 2019年7月16日 下午3:01:34
*/
public class Chat {
static private CopyOnWriteArrayList<Channel> all = new CopyOnWriteArrayList<Chat.Channel>();
static int i=0; public static void main(String[] args) throws IOException {
System.out.println("=====Server=====");
//1、指定端口号 使用ServerSocket创建服务器 监听端口9999
ServerSocket server = new ServerSocket(9999); //2、阻塞式等待连接accept
while (true) {
Socket client = server.accept();
System.out.println("建立"+(++i)+"连接");
Channel c = new Channel(client);
all.add(c);//管理所有的成员
new Thread(c).start();
}
} /**
*
* @ClassName: Channel
* @Description: 一个client代表一个channel
* @author ganquanzhong
* @date 2019年7月16日 下午5:49:02
*/
static class Channel implements Runnable{
private DataInputStream dis ;
private DataOutputStream dos ;
private Socket client;
private boolean isRunning;
private String name; public Channel(Socket client) {
this.client=client;
try {
dis = new DataInputStream(client.getInputStream());
dos = new DataOutputStream(client.getOutputStream());
isRunning=true;
//获取名称
this.name=receive();
this.send("欢迎来到ForFuture群聊系统!");
sendOthers(this.name+"上线了", true);
} catch (IOException e) {
System.out.println("---初始化错误----");
release();
e.printStackTrace();
}
} //接收消息
private String receive() {
String msg="";
try {
msg= dis.readUTF();
} catch (IOException e) {
System.out.println("---接收消息错误----");
release();
e.printStackTrace();
}
return msg;
} //发送消息
private void send(String msg) {
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
System.out.println("---发送消息错误----");
release();
e.printStackTrace();
}
} /**
* 群聊:获取自己的消息,发送给别人
* 私聊:约定数据格式 @:名称:msg
*
* @Title: sendOthers
* @Description: TODO(这里用一句话描述这个方法的作用)
* @author ganquanzhong
* @date 2019年7月17日 上午9:16:44
* @param msg
* @param isSys
*/
private void sendOthers(String msg,boolean isSys) {
boolean isPrivate = msg.startsWith("@");
if (isPrivate) {
//私聊
int idx1 = msg.indexOf(":");
int idx2 = msg.indexOf(":");
int idx = idx1 != -1?idx1:idx2;
String targetName = msg.substring(1, idx);
msg = msg.substring(idx+1);
for(Channel other :all) {
if (other.name.equals(targetName)) {
other.send("\n\t"+new SimpleDateFormat("YYYY-MM-dd HH:MM:ss SSS").format(new Date()) +"\n"
+this.name+": "+msg);
break;
}
}
}else {
//群聊
for(Channel other:all) {
if (other == this) {//本身
continue;
}
if (!isSys) {
other.send("\n\t"+new SimpleDateFormat("YYYY-MM-dd HH:MM:ss SSS").format(new Date()) +"\n"
+this.name+": "+msg);
}else {
other.send("\n\t"+new SimpleDateFormat("YYYY-MM-dd HH:MM:ss SSS").format(new Date()) +"\n"
+"系统消息"+": "+msg);
}
}
}
} //释放资源
private void release () {
this.isRunning = false;
Utils.close(dis,dos,client);
//退出
all.remove(this);
sendOthers(this.name+"离开了!", true);
} @Override
public void run() {
while(isRunning) {
String msg = receive();
if (!msg.equals("")) {
//send(msg);
sendOthers(msg,false);
}
}
}
}
}

客服端LoginMultiServer.class

package com.gqz.chat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException; /**
* 在线聊天
* 封装 实现多用户聊天
*
* @ClassName: Client
* @Description: TODO(这里用一句话描述这个类的作用)
* @author ganquanzhong
* @date 2019年7月16日 下午3:01:07
*/
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("\t进入群聊系统 输入您的用户名称:");
String name = br.readLine();
System.out.println("=====client="+name+"====");
// 1、建立面向连接:使用Socket创建客户端 (服务器地址和端口)
Socket client = new Socket("localhost", 9999); //客户端发送消息
new Thread(new Send(client,name)).start(); //客户端接收消息
new Thread(new Receive(client)).start();
}
}

Send.class

package com.gqz.chat;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket; /**
* 使用多线程封装:发送端
* 1、发送消息
* 2、从控制台获取消息
* 3、释放资源
* 4、重写run
*
* @ClassName: Send
* @Description: TODO(这里用一句话描述这个类的作用)
* @author ganquanzhong
* @date 2019年7月16日 下午5:09:16
*/
public class Send implements Runnable {
private BufferedReader console;
private DataOutputStream dos;
private Socket client;
private boolean isRunning;
private String name; public Send(Socket client,String name) {
this.client = client;
isRunning=true;
this.name= name;
console = new BufferedReader(new InputStreamReader(System.in));
try {
dos = new DataOutputStream(client.getOutputStream());
//发送名称
send(name);
} catch (IOException e) {
System.out.println("====初始化错误====");
this.release();
e.printStackTrace();
}
} // 发送消息
private void send(String msg) {
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
System.out.println("--client-发送消息错误----");
release();
e.printStackTrace();
}
} // 从控制台获取消息
private String getFromConsole() {
try {
return console.readLine();
} catch (IOException e) {
System.out.println("=====console error=====");
e.printStackTrace();
}
return "";
} // 释放资源1
private void release() {
this.isRunning = false;
Utils.close(dos, client);
} @Override
public void run() {
while (isRunning) {
String msg = getFromConsole();
if (!msg.equals("")) {
send(msg);
}
}
}
}

Receive.class

package com.gqz.chat;

import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket; /**
* 使用多线程封装:接收端
* 1、接收消息
* 2、释放资源
* 3、重写run
*
* @ClassName: Receive
* @Description: TODO(这里用一句话描述这个类的作用)
* @author ganquanzhong
* @date 2019年7月16日 下午5:08:34
*/
public class Receive implements Runnable {
private DataInputStream dis;
private Socket client;
private boolean isRunning; public Receive(Socket client) {
this.client = client;
isRunning=true;
try {
dis = new DataInputStream(client.getInputStream());
} catch (IOException e) {
System.out.println("====client 接收消息 初始化错误=====");
release();
e.printStackTrace();
}
} // 接收消息
private String receive() {
String msg = "";
try {
msg = dis.readUTF();
} catch (IOException e) {
System.out.println("---client 接收消息错误----");
release();
e.printStackTrace();
}
return msg;
} // 释放资源1
private void release() {
this.isRunning = false;
Utils.close(dis, client);
} @Override
public void run() {
while(isRunning) {
String msg = receive();
if (! msg.equals("")) {
System.out.println(msg);
}
}
}
}

Utils.class

package com.gqz.chat;

import java.io.Closeable;

/**
* 工具类
*
* @ClassName: Utils
* @Description: TODO(这里用一句话描述这个类的作用)
* @author ganquanzhong
* @date 2019年7月16日 下午4:25:10
*/
public class Utils {
/*
* 释放资源
*/ public static void close(Closeable... targets) {
for(Closeable target:targets) {
try {
if (null != target) {
target.close();
}
}catch(Exception e) {
}
}
} }

项目下载:https://github.com/gqzGitHub/Net_study

网络编程UDP、TCP详解的更多相关文章

  1. Java网络编程和NIO详解开篇:Java网络编程基础

    Java网络编程和NIO详解开篇:Java网络编程基础 计算机网络编程基础 转自:https://mp.weixin.qq.com/s/XXMz5uAFSsPdg38bth2jAA 我们是幸运的,因为 ...

  2. Java网络编程和NIO详解9:基于NIO的网络编程框架Netty

    Java网络编程和NIO详解9:基于NIO的网络编程框架Netty 转自https://sylvanassun.github.io/2017/11/30/2017-11-30-netty_introd ...

  3. Java网络编程和NIO详解4:浅析NIO包中的Buffer、Channel 和 Selector

    Java网络编程与NIO详解4:浅析NIO包中的Buffer.Channel 和 Selector 转自https://www.javadoop.com/post/nio-and-aio 本系列文章首 ...

  4. Java网络编程和NIO详解3:IO模型与Java网络编程模型

    Java网络编程和NIO详解3:IO模型与Java网络编程模型 基本概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32 ...

  5. Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制

    Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制 JAVA 中原生的 socket 通信机制 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.co ...

  6. Java网络编程和NIO详解6:Linux epoll实现原理详解

    Java网络编程和NIO详解6:Linux epoll实现原理详解 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NIO h ...

  7. Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO

    Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO Java 非阻塞 IO 和异步 IO 转自https://www.javadoop.com/post/nio-and-aio 本系 ...

  8. Java网络编程和NIO详解8:浅析mmap和Direct Buffer

    Java网络编程与NIO详解8:浅析mmap和Direct Buffer 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NI ...

  9. Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理

    Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理 转自:https://www.jianshu.com/p/2b71ea919d49 本系列文章首发于我的个人博 ...

  10. Java网络编程和NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型

    Java网络编程与NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型 知识点 nio 下 I/O 阻塞与非阻塞实现 SocketChannel 介绍 I/O 多路复用的原理 事件选择器与 ...

随机推荐

  1. 【iOS】Spring Animations (弹性动画)

    This interface shows how a spring animation can be created by specifying a “damping” (bounciness) an ...

  2. 浅析 .NET 中 AsyncLocal 的实现原理

    目录 前言 1.线程本地存储 2.AsyncLocal 实现 2.1.主体 AsyncLocal<T> 2.2.AsyncLocal<T> 在 ExecutionContext ...

  3. 谷歌BBR拥塞算法内核更新

    为什么想到这个呢,算法什么的又不太懂,这是 因为搭建VPN + BBR 与之简直绝配 有的人搭建SSR ,配一个什么锐速,还需要降内核版本, 而且还容易出错,降了之后更加容易出现兼容性问题,所以偶尔看 ...

  4. Linux下VIM编译器的使用以及shell编程基础

    VIM编译器的安装与使用 vim编辑器安装 在CentOS中,执行:yum -y install vim 普通模式 h: 左移一个字符 j: 下移一行 k: 上移一行 l: 右移一个字符 PageDo ...

  5. 044.Python线程的数据安全

    线程的数据安全 1 数据混乱现象 from threading import Thread,Lock num = 0 lst = [] def func1(): global num for i in ...

  6. js有关字符串拼接问题

    我们经常写代码要遇见要拼接字符串,比如说我们要把     "yyy" 和一个动态数字拼接,接下来我们怎么办? 其实我们都会想到直接用“yyy”  + 一个数字不就可以了吗? 对的, ...

  7. ArchLinux下electronssr无法启动的解决措施

    ArchLinux下electronssr无法启动的解决措施 今天重新配置electron-ssr时发现闪退(无法启动). 于是开始查错 首先是找到了目录位置 /usr/electron-ssr/el ...

  8. windows下安装openjdk

    redhat版openjdk,解压后就能用,下载地址https://developers.redhat.com/products/openjdk/download. Azul Zulu版openjdk ...

  9. 代数式到c语言表达式和常用的c语言数学库函数_pow_sqrt_exp_fabs_abs

    数学知识来源于生活,因此我们需要把相关的数学的知识在自己生活找到实例. #include "common.h" #include <stdio.h> #include ...

  10. JSP+Servlet+Ajax实现用户增删改查的例子

    一.数据库设计 用户表User 已有的测试数据 二.Java代码编写 Java EE的架构一般分为以下五层: ①.Domain ②.DAO ③.Service ④.Controller ⑤.View ...