TCP/IP 模型。一组用于实现网络互连的通信协议,将协议分成四个层次。应用层、传输层、网络层、网络接口层。
TCP,Transmission Control Protocol,传输控制协议。是一种面向连接的、可靠的、基于字节流的传输层通信协议。数据大小无限制。建立连接的过程需要三次握手,断开连接的过程需要四次挥手。
UDP,User Datagram Protocol,用户数据报协议。是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,每个包的大小64KB。
IP协议,Internet Protocol Address,互联网协议地址/网际协议地址。分配给互联网设备的数字标签(唯一标识)。IP地址分为两种。IPV4,分成4段8位的二进制数;IPV6,分成8段十六进制数。
Port,端口号。在通信实体上进行网络通讯的程序的唯一标识。
InetAddress 类。
public class Test {
public static void main(String[] args) throws UnknownHostException {
// TODO Auto-generated method stub
// 获得本地主机地址对象
System.out.println(InetAddress.getLocalHost());
// 根据主机名称获得地址对象
System.out.println(InetAddress.getByName("baidu.com"));
// 获得所有相关地址对象
InetAddress[] all = InetAddress.getAllByName("baidu.com");
for (InetAddress inetAddress : all) {
System.out.println(inetAddress);
}
for (InetAddress inetAddress : all) {
System.out.println("获取IP地址字符串 " + inetAddress.getHostAddress());
// 获得IP地址主机名
System.out.println("获取IP地址主机名 " + inetAddress.getHostName());
}
}
}
基于TCP的网络编程,Socket编程。Socket(套接字)是网络中的一个通信节点。分为客户端 Socket 与服务器 ServerSocket。
封装一个关闭流的通用方法。将 Closeable 接口作为泛型参数。
public class PublicMethod {
public PublicMethod() {
}
public static void closeAll(Closeable... hh) {
for (Closeable closeable : hh) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
TCP 编程实现客户端发送数据给服务器端。
// 服务端
public class TestServer {
public TestServer() {
}
public static void main(String[] args) throws IOException {
ServerSocket ssocket = new ServerSocket(9527);
// 与客户端建立连接
Socket socket = ssocket.accept();
System.out.println("等待客户端输入");
InputStream ins = socket.getInputStream();
byte[] bt = new byte[1024];
// 接收客户端发来的数据
int len = ins.read(bt); // 阻塞,接收到数据才往下走
System.out.println(new String(bt, 0, len));
OutputStream ous = socket.getOutputStream();
// 向客户端发送数据
ous.write("不在。".getBytes());
PublicMethod.closeAll(ous, ins, socket, ssocket);
}
}
// 客户端
public class TestClient {
public TestClient() {
}
public static void main(String[] args) throws UnknownHostException, IOException {
// 本地 ip 用来测试
Socket socket = new Socket("127.0.0.1", 9527);
System.out.println("客户端已连接");
OutputStream os = socket.getOutputStream();
// 向服务端发送数据
os.write("在吗?".getBytes());
InputStream ins = socket.getInputStream();
byte[] bt = new byte[1024];
// 接收服务端发来的数据
int len = ins.read(bt); // 阻塞,接收到数据才往下走
System.out.println(new String(bt, 0, len));
PublicMethod.closeAll(ins, os, socket);
}
}
TCP 编程实现客户端上传文件给服务器端。
public class TestServer {
public TestServer() {
}
public static void main(String[] args) throws IOException {
ServerSocket ssocket = new ServerSocket(8000);
Socket socket = ssocket.accept();
//输入流接收客户端数据
InputStream ins = socket.getInputStream();
// 随机文件名
Double num = Math.random() * 1000000;
String name = num.toString();
// 输出流输出数据到文件
OutputStream ous = new FileOutputStream("/Users/mac/Desktop/image备份/"+ name +".jpg");
byte[] bt = new byte[1024];
int len = ins.read(bt);
while (len != -1) {
ous.write(bt, 0, len);
// 循环读取客户端数据, 阻塞,接收到数据才往下走
len = ins.read(bt);
}
PublicMethod.closeAll(ous, ins, socket);
}
}
public class TestClient {
public TestClient() {
// TODO Auto-generated constructor stub
}
public static void main(String[] args) throws UnknownHostException, IOException {
// 本地 ip 用来测试
Socket socket = new Socket("127.0.0.1", 8000);
// 输入流打开文件取数据
InputStream ins = new FileInputStream("/Users/mac/Desktop/熊本熊/8ad0576698b03ee5014d880713d4d054.jpg");
// 输出流向服务端发送输入流中取出的数据
OutputStream ous = socket.getOutputStream();
byte[] bt = new byte[1024];
int len = ins.read(bt);
while (len != -1) {
// 循环向服务端发送数据
ous.write(bt, 0, len);
len = ins.read(bt);
}
PublicMethod.closeAll(ous, ins, socket);
}
}
TCP 实现多个客户端发送数据给服务器端。需要多线程,每连接一个客户端,开辟一个新线程。
// 自定义多线程
public class ServerThread extends Thread {
private Socket s;
public ServerThread() {
}
public ServerThread(Socket s) {
super();
this.s = s;
}
@Override
public void run() {
BufferedReader in = null;
try {
// 字符缓冲输入流接收客户端数据
in = new BufferedReader(new InputStreamReader(s.getInputStream()));
// 注意: 服务端循环是为了多个客户端连接,这里的循环是为了循环接收同一个客户端的多次输入
while (true) {
String hh = in.readLine();
System.out.println(s.getInetAddress() + " 说 " + hh);
if (hh.equals("886")) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
PublicMethod.closeAll(in, s);
}
}
public Socket getS() {
return s;
}
public void setS(Socket s) {
this.s = s;
}
}
// 服务端
public class TestServer {
public TestServer() {
}
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(8000);
// 死循环监听客户端,目的就是处理多个客户端的访问,需要有多个服务器连接
while (true) {
// 阻塞,连接后开辟线程
Socket socket = ss.accept();
// 自定义多线程接收 socket
ServerThread st = new ServerThread(socket);
st.start();
}
}
}
// 客户端
public class TestClient {
public TestClient() {
// TODO Auto-generated constructor stub
}
public static void main(String[] args) throws UnknownHostException, IOException {
Socket s = new Socket("127.0.0.1", 8000);
System.out.println("客户端已连接");
Scanner input = new Scanner(System.in);
// 字符缓冲输出流提升效率,桥接流连接字节流和字符流
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
while (true) {
System.out.println("请输入:");
String res = input.next();
out.write(res);
out.newLine();
// 刷新字符从缓冲区到业务区
out.flush();
if (res.equals("886")) {
break;
}
}
PublicMethod.closeAll(out, s);
}
}