先展示一套简单的网络通信代码
/*
* 客户端建立思路:
* 1.创建TCP客户端socket服务,使用的是socket对象
* 2.如果连接成功,说明数据传输通过建立
* 通过就是socket流,是底层建立好的
* 是流就应该由输入和输入。
* 想要获取输入或者输入流对象,可以找socket获取
* 可以通过getOutputStream()和getInputStream()来获取两个字节流
* 3.使用输入流吗,将数据写入。
* 4.关闭资源
*/
public class Client {
public static void main(String[] args) {
try {
// Socket(String host,int port);
//1.创建Socket对象,指定服务器的IP地址和端口号
Socket s = new Socket("localhost", 8888);
//建立连接后,通过socket中的IO流进行数据传输
//向服务器发送 你好,服务器
//如果想要使用字符流 需要使用OutputStreamWriter/InputStreamWriter 转换流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
bw.write("你好,服务器");
bw.flush();
s.shutdownOutput();
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String str = br.readLine();
System.out.println("服务器端发来的消息是:"+str);
s.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
* 建立TCP服务器端思路:
* 1.创建服务器socket服务。通过ServerSocket对象
* 2.服务器端必须对外提供一个端口,否则客户端无法连接
* 3.获取连接过来的客户端对象
* 4.通过客户端对象获取socket流读取客户端发来的数据打印
* 5.关闭资源、关闭流、关闭服务器
*
*/
public class Server {
public static void main(String[] args) {
try {
//1.创建ServerSocket类型的对象,指定接口
ServerSocket ss = new ServerSocket(8888);
System.out.println("等待客户端连接....");
//等待客户端连接,使用accept()
Socket s = ss.accept();//进行阻塞
System.out.println("客户端连接成功....");
//使用字符缓冲输入流接收客户端消息
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String str = br.readLine();
System.out.println("客户端发来的消息是:"+str);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
bw.write("客户端你好呀!");
bw.newLine();
bw.close();
br.close();
s.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
java生下来一开始就是为了计算机之间的通信,因此这篇文章也将开始介绍一下java使用socket进行计算机之间的通信,在上一篇文章中已经对网络通信方面的基础知识进行了总结,这篇文章将通过代码案例来解释说明。
一、网络编程基础
因为java网络编程这块是从基础开始讲解的,所以知识点也是由浅入深,因此还是有必要对一些基础的知识进行回顾和掌握,如果你是大神,不喜勿喷。
1、两台计算机之间的通信
两台计算机如何实现通信呢?人类交流是通过定义一定的语言,计算机也是,他们之间必须要有相应的协议才可以。
也就是说,两台计算机要想通信必须要遵循一定的规则协议。通信流程基本上就是,一台计算机上的一个端口号数据,然后通过协议发送到另外一台计算机上的同一个端口号。这里面有三个重要的部分需要我们去理解一下,当然不会细讲,因为在上一篇文章中已经提出。
(1)TCP/IP协议
(2)IP地址
(3)端口
我们先讲一下TCP/IP模型。
2、TCP/IP模型
TCP/IP模型就是上面的协议,它定义了一些规则来用于计算机之间的通信,同时也是世界上应用最为广泛的协议。这个协议模型建立在TCP和IP协议上面(从名字也可以看出来)。
从上图我们可以看到TCP/IP其实是处于传输层的,也就是我们的协议核心所在,TCP/IP协议定义了电子设备如何连入因特网,以及数据如何在它们之间传输的标准。
3、IP地址
为了实现两个网络中不同计算机之间的通信,每台计算机都必须有一个唯一的标识,就是中国公民每一个人都有一个惟一的身份证号码一样。
4、端口
我们知道一台计算机其实是可以跑很多个程序的,那么我们的程序怎么就能准确无误的到达另外一个程序呢?这其实就是使用了端口号来区分不同的应用程序。
端口号的范围也很大0到65535。其中0到1023是保留的,也就是我们不能用的。那我们的今天所讲的socket是如何组成的呢?其实就是由IP地址和端口号组成的。
二、socket通信
在上面其实我们对通讯需要掌握的一些基础知识进行了分析,这里我们开始使用java语言来演示一下这个过程。
socket通信其实是有两种方式:TCP和UDP过程。
(1)TCP是可靠地面向连接的通信过程,含有三次握手四次挥手的机制。
(2)UDP是不可靠的无连接的通信过程,客户端只管发,不管服务端有没有接受到。
那这两种通信方式的基本模型是什么呢?我们使用一张图来看一下:、
从上图我们可以看到,Socket实现的步骤大体包含以下几个步骤:
(1)创建Server和client的ServerSocket和Socket。
(2)打开链接到Socket的输入输出流
(3)按照协议对Socket进行读取操作
(4)关闭输入输出流、关闭Socket。
下面我们就直接来看例子,然后再来分析这个例子:
1、基于TCP的socket通信
我们拿男孩做客户端,女孩因为有很多人追求,所以做服务端,一个服务端可被多个男孩客户端请求表白。我们这里先看女孩服务端的具体步骤:
(1)创建ServerSocket对象,绑定监听端口。
(2)通过accept()方法监听客户端请求
(3)连接建立后,通过输入流读取客户端的数据
(4)通过输出流,向客户端回应信息
下面是一套传输文件的
public class Server {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(8888);
System.out.println("等待客户端上传文件。");
Socket s = ss.accept();
InputStream is = s.getInputStream();
//创建字节输出流向指定服务器中输入用户上传的文件
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("5.jpg"));
byte[] by =new byte[1024*8];
BufferedInputStream bis = new BufferedInputStream(s.getInputStream());
int num = 0;
while((num = bis.read())!= -1){
bos.write(by, 0, num);
bos.flush();
}
bos.close();
bis.close();
s.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class Client {
public static void main(String[] args) {
try {
Socket s = new Socket("localhost",8888);
//读取本地文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("e://4.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());
//创建缓冲去
byte[] by = new byte[1204*8];
int num = 0;
//读取本地文件
while((num = bis.read())!=-1){
//将本地读取的数据写入指定服务器
bos.write(by,0,num);
bos.flush();
}
bos.close();
bis.close();
s.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
下面是获取ip地址等
//1.获取本机的主机地址和IP地址信息
try {
InetAddress ia = InetAddress.getLocalHost();
//自动调用toString(); 字符串的格式:主机名/IP地址
System.out.println(ia);//LAPTOP-QOPMUIA9/127.0.0.1
//拆分地址信息分别获取主机名和IP地址 分别打印
System.out.println(ia.getHostName());//LAPTOP-QOPMUIA9
System.out.println(ia.getHostAddress());//127.0.0.1
//2.获取指定主机名中的地址信息
InetAddress ia2 = InetAddress.getByName("LAPTOP-QOPMUIA9");
System.out.println(ia2);
System.out.println(ia2.getHostName());
System.out.println(ia2.getHostAddress());
} catch (UnknownHostException e) {
e.printStackTrace();
}
下面是一套类似聊天室的代码
public static void main(String[] args) {
try {
Socket socket = new Socket("localhost", 8099);
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedReader br2 = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintStream printStream = new PrintStream(socket.getOutputStream());
while (true) {
System.out.println("请输入要发送的内容~!");
String readLine = br.readLine();
printStream.println(readLine);
System.out.println("客户端已发送,内容是:" + readLine);
String readLine2 = br2.readLine();
// 大小写铭感的问题
if (readLine2.equalsIgnoreCase("by")) {
break;
}
System.out.println("服务器端说:" + readLine2);
}
br2.close();
br.close();
printStream.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
服务器
public class ServerThread extends Thread {
private Socket socket;
public ServerThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintStream printStream = new PrintStream(socket.getOutputStream());
while (true) {
String readLine = br.readLine();
if (readLine.equalsIgnoreCase("by")) {
break;
}
printStream.println(readLine);
System.out.println(socket.getInetAddress() + "客户端说的是" + readLine);
printStream.print("我是服务端");
System.out.println("服务器已经发送");
}
br.close();
printStream.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class ServerTest {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(8099);
while (true) {
System.out.println("等待客户端连接");
Socket socket = serverSocket.accept();
System.out.println("来了一个" + socket.getInetAddress());
new ServerThread(socket).start();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
UDP的通信模式其实是无连接的不可靠的通信协议,举个例子,不管对方有没有收到信息,自己继续像其他发送信息。
我们首先来看一下服务端的步骤:
接收客户端发送的数据
(1)创建服务器端DatagramSocket指定端口
(2)创建数据报DatagramPacket,接收客户端发送的数据
(3)接收客户端发送的数据
(4)读取数据
向客户端响应数据
(1)定义客户端的地址、端口号、数据
(2)创建数据报,包含响应的数据信息
(3)响应客户端
(4)关闭资源
public class TestReceive {
public static void main(String[] args) throws Exception {
//1.创建DatagramSocket类型的对象,并提供端口号
DatagramSocket ds = new DatagramSocket(8888);
//2.创建DatagramPacket类型的对象,用于接收数据内容
byte[] data = new byte[1024];
DatagramPacket dp = new DatagramPacket(data, data.length);
//3.接收数据并保存到数据报中,使用receive()方法
ds.receive(dp);
System.out.println("接收到的数据是:"+new String(data,0,dp.getLength())+"!");
//4.关闭套接字
ds.close();
}
}
public class TestSend {
public static void main(String[] args) throws Exception {
// 1.创建DatagramSocket类型的对象
DatagramSocket ds = new DatagramSocket();
// 2.创建DatagramPacket类型的对象,提供接收方的端口号和IP地址
byte[] data = "hello".getBytes();
InetAddress ia = InetAddress.getLocalHost();
DatagramPacket dp = new DatagramPacket(data, data.length, ia, 8888);
// 3.发送数据内容,使用send()方法
ds.send(dp);
System.out.println("成功发送数据内容");
// 4.关闭套接字
ds.close();
}
}