在不同计算机之间进行通信时,需要具备拥有唯一标识的ip地址以及端口号,每个ip地址对应一台主机,每台主机上有65536个端口号,每个端口号能且只能承载一个进程的运行。
要进行网络通信时,就要了解一个新的概念—socket(套接字),用于描述IP地址和端口号,是一个通信链的句柄。应用程序通常使用套接字来向网络发出请求或应答网络请求,也不易实现不同虚拟机或计算机之间的通信。socket的英文含义原指“插座”,所以如果将每一台主机比喻成一个房间,那么socket就是房间里存在的多个插座,每个插座具有不同的编号,并提供不同的电流,这样保证了不同的socket可以对外提供不同的服务。
有了通信的“介质”后,还需要遵循某种协议才能正常进行,这种协议就是基于IP协议的TCP协议和UDP协议。
一、UDP协议(User Datagram Protocol)
1、特点
UDP协议指客户端向服务端发送一个数据包,但对于服务端是否能收到数据不作处理。
(1)将数据即源和目的封装成数据包,不需要建立连接
(2)每个数据报的大小限制在64k
(3)不可靠协议
(4)速度快
2、使用
(1)发送端
步骤:
①建立udp服务
②提供数据,并将数据封装到数据包中
③通过socket服务的发送功能,将数据包发送出去
④关闭资源
package 网络编程;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UdpSend {
public static void main(String[] args) throws Exception {
//创建DatagramSocket对象指定发送端端口号
DatagramSocket socket = new DatagramSocket(5000);
//调用InetAddress类的getByName方法,通过指定主机名来获取接收端IP地址
InetAddress address = InetAddress.getByName("127.0.0.1");
//指定发送的数据
String str = "hello world!";
byte[] buff = str.getBytes();
//将数据封装到DatagramPacket对象中,并指定接收端的IP地址和端口号,然后发送
DatagramPacket packet = new DatagramPacket(buff, buff.length,address,8255);
socket.send(packet);
if(socket!=null)
socket.close();
}
}
(2)接收端:
步骤:
①定义udp的socket服务
②定义一个数据包,因为要存储接收到的字节数据,可以提取数据中的不同信息
③通过socket服务的receive方法收到的数据存到已定义好的数据包中
④取数据,然后关闭资源
package 网络编程;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UdpReceive {
public static void main(String[] args) throws Exception{
//创建DatagramSocket对象指定接收端端口号
DatagramSocket socket = new DatagramSocket(8255);
//将接收的数据存在DatagramPacket对象中
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf,buf.length);
socket.receive(packet);
//使用DatagramPacket中的方法来获取发送端的IP地址和端口号
String ip = packet.getAddress().getHostAddress();
int port = packet.getPort();
String data = new String(packet.getData(), 0, packet.getLength());
System.out.print("数据是:"+data+"ip是:"+ip+"端口是:"+port);
socket.close();
}
}
对上面的程序进行测试,先运行接收端程序,然后运行发送端程序,可以看到数据发送过去并显示发送端信息(ip地址和端口号)
二、TCP协议(Transfer Control Protocol(传输控制协议))
1、特点
TCP协议请求网络时会经历“三次握手”,指客户端向服务端发送请求,然后服务端收到请求后回应客户端已收到,最后客户端向服务端发送数据。
(1)建立连接,形成传输数据的通道
(2)在连接中进行大数据量传输
(3)通过三次握手完成连接,可靠协议
(4)必须建立连接,效率会降低
2、使用
(1)客户端
步骤:
①创建socket服务,Socket,连接服务端地址并指定端口
②获取写入输出流,并写入数据
package 网络编程;
/*
* 需求:客户端输入的字符串发送给服务器端,然后将大写格式返回给客户端
*
* TCP客户端,提供输出流
*/
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class TcpClient {
public static void main(String[] args) throws Exception, IOException {
//创建客户端Socket指定服务器端主机和端口号
Socket socket = new Socket("127.0.0.1", 5698);
//获取键盘输入的数据
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
//获取网络输出流,用于向网络上写数据
OutputStream os = socket.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
//获取网络输入流,用于接收网络数据
InputStream is = socket.getInputStream();
BufferedReader br1 = new BufferedReader(new InputStreamReader(is));
/*
* 下面代码为读取键盘输入数据
* 并将其写入网络流用于服务器
* 端的接收,服务器接收到后
*
*/
String line = null;
while((line = br.readLine())!= null){
if(line.equals("over"))
break;
bw.write(line);
bw.newLine();
bw.flush();
String len = br1.readLine();
System.out.println(len);
}
System.out.println("已收到");
Thread.sleep(5000);
br.close();
socket.close();
}
}
(2)服务器端
步骤:
①建立服务端socket服务,serverSocket,并监听一个 端口
②获取连接过来的客户端对象,通过调用accept方法,阻塞式方法
③获取一个读取输入流
package 网络编程;
/*
* TCP服务器端
*
*
*/
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) throws Exception {
//创建服务器端Socket并指定该服务器端口号
ServerSocket ss = new ServerSocket(5698);
//获取客户端Socket对象
Socket socket = ss.accept();
//获取网络输入流
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//获取网络输出流
OutputStream os = socket.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
//使用打印流输出
// PrintStream ps = new PrintStream(os,true);
//获得客户端发送的数据后并向客户端返回数据
String line=null;
while((line = br.readLine())!=null){
// ps.println(line.toUpperCase());
bw.write(line.toUpperCase());
bw.newLine();
bw.flush();
}
System.out.println("已发送");
ss.close();
}
}
下面为测试结果:
三、使用Socket自定义浏览器向tomcat服务器发送Http请求
“`
package clientandserver;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
/*
*
* 自定义浏览器
*
*/
public class DesignBrowns {
public static void main(String[] args) throws Exception{
Socket socket = new Socket("192.168.238.2", 8080);
PrintStream out = new PrintStream(socket.getOutputStream(),true);
out.println("GET /myweb/wk.html HTTP/1.1");
out.println("*/*");
out.println("Accept-Language: zh-CN");
out.println("Host: 192.168.238.2:11000");
out.println("Connection: closed");
//使用空行将请求头和请求体隔开
out.println();
out.println();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
while((line = br.readLine())!= null){
System.out.println(line);
}
br.close();
socket.close();
}
}
这里访问服务器的一个html文件,服务器返回响应数据以及文件数据,只是该“浏览器”没有解析html的功能,所以只能原样输出。
“`
四、自定义服务器
package clientandserver;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
/*
*
* 自定义服务端
*
*/
public class DesignServer {
public static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(11000);
Socket socket = ss.accept();
String ip = InetAddress.getLocalHost().getHostAddress();
InputStream is = socket.getInputStream();
byte[] buf = new byte[1024];
int len= is.read(buf);
System.out.println(new String(buf,0,len));
// BufferedWriter bw = new BufferedWriter(new OutputStreamWriter
// (socket.getOutputStream()));
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println("<font size='7' color='red'>这是一个自定义的服务器!</font>");
ps.close();
// bw.write("<font size='7' color='red'>nihao</font>");
// bw.newLine();
ss.close();
// bw.close();
}
}