JAVA网络编程
网络模型
OSI参考模型
应用层:终端的应用
表示层:对接收数据进行 解释、加密和解密、压缩和解压等
会话层:通过传输层建立数据传输的通路
传输层:定义了一些数据传输的协议和端口号(WWW端口80等),如:TCP(传输控制协议) UDP(用户数据包协议)
网络层:将从下层接受的数据进行IP地址的封装和解封装(路由器,数据包)
数据链路层:从物理层接受的数据进行MAC地址的封装和解封转(交换机)
物理层:作用传输比特流,数模转换,模数转化
TCP/IP
应用层
传输层
网际层
主机至网络层
网络通讯要素
IP地址
网络中的设备标识
不易记忆,可用主机名
本地回环地址:127.0.0.1 主机名:localhost
端口号
用于标识进程的逻辑地址,不同进程的标识
有效端口:0~65535 ,其中0~1024系统使用或保留端口
DNS(域名解析服务)
通讯协议
通讯的规则
常见协议:TCP,UDP
Socket(网络服务机制)
通信的两端都有Socket
UDP
将数据及源和目的封装成数据包中,不需要建立连接
每个数据包的大小限制在64k内
因无连接,是不可靠协议
不需要建立连接,速度快
UDP协议--发送端
创建UDP传输的发送端
思路:
1、建立udp的socket服务
2、将要发送的数据封装到数据包中
3、通过udpde的socket发送出去
4、关闭socket服务
DatagramSocket ds = new DatagramSocket();
String str = "udp传输演示:狗子,你好!";
byte[] buf = str.getBytes();
DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("未央"),10000);
ds.send(dp);
ds.close();
接收端
创建UDP传输的接收端
思路:
1、建立udp的socket服务
2、创建数据包,存储接收的数据,方便解析数据
3、通过数据包方法解析数据包中数据
4、关闭socket服务
package com.udp;
import java.io.IOException;
import java.net.*;
/**
* 创建UDP传输的接收端
* 思路:
* 1、建立udp的socket服务,必须指定端口号
* 2、创建数据包,存储接收的数据,方便解析数据
* 3、通过数据包方法解析数据包中数据
* 4、关闭socket服务
* @author Administrator
*
*/
public class UDPReceive {
public static void main(String[] args) throws IOException {
System.out.println("UDP接收端开启...");
DatagramSocket ds = new DatagramSocket(10000);
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
ds.receive(dp);
String ip = dp.getAddress().getHostAddress();
int port = dp.getPort();
String text = new String(dp.getData(),0,dp.getLength());
System.out.println(ip+" "+port+" "+text);
ds.close();
}
}
TCP
TCP
建立连接,形成传输数据的通道
在连接中进行大数据传输
通过三次握手完成连接,是可靠协议
必须建立连接,效率会稍低
客户端:
1、建立客户端的socket服务
2、获取socket流中的输出流
3、使用输出流将指定的数据发送出去
4、关闭资源
package com.tcp;
import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* TCP客户端
* @author Administrator
*
*/
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
//使用IP和端口定义客户端Socket
Socket client = new Socket("127.0.0.1", 10002);
//如果连接建立,数据通道已建立 通道: ScoketIO流是底层建立好的,既有输入又有输出
//创建输入输出流对象
InputStream in = client.getInputStream();
OutputStream out = client.getOutputStream();
//发送数据给服务端
String str = "TCP客户端发送的消息!";
System.out.println("客户端发送:\n"+str);
byte []b = str.getBytes();
out.write(b);
//接收服务端返回的数据
System.out.println("客户端接收:");
byte[] buf = new byte[1024];
int length = in.read(buf);
String text = new String(buf, 0, length);
System.out.println(text);
in.close();
out.close();
client.close();
}
}
服务端
1、建立服务端的socket服务
2、服务端必须提供一个端口,否则无法连接
3、使用输入流接收指定的数据
4、关资源、关闭客户端、关闭服务端
package com.tcp;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* TCP服务端(必须先启动服务端)
* @author Administrator
*
*/
public class Server {
public static void main(String[] args) throws IOException {
//定义监听对象
ServerSocket listen = new ServerSocket(10002);
//定义server套接字
Socket server = listen.accept();
String ip = server.getInetAddress().getHostAddress();
//创建输入流对象,接收客户端
InputStream in = server.getInputStream();
//创建输出流对象,返回给客户端
OutputStream out = server.getOutputStream();
System.out.println("服务端接收:");
//接收客户端的数据
byte[] buf = new byte[1024];
int length = in.read(buf);
String text = new String(buf, 0, length);
System.out.println(ip+" "+text);
//返回客户端数据
String str = "TCP服务端返回的消息!";
System.out.println("服务端发送:"+str);
byte []b = str.getBytes();
out.write(b);
//关资源
in.close();
out.close();
//关闭客户端
server.close();
//关闭服务端(一般不关闭)
listen.close();
}
}
练习:文本转换
需求:客户端发送字母,服务端转换为大写传回客户端
客户端:
思路:
1、建立客户端的socket
2、数据输入
3、数据发送
4、接收服务端返回数据
package com.test;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
/**
* 大写转换客户端
* @author Administrator
*
*/
public class ToUpperClient {
public static void main(String[] args) throws Exception {
Socket socket = new Socket("127.0.0.1",8877);
@SuppressWarnings("resource")
Scanner scanner = new Scanner(System.in);
while(true){
System.out.println("输入要转换为大写的数据:");
String line = scanner.nextLine();
//创建一个新的打印流, 此流不会自动刷新
PrintStream print = new PrintStream(socket.getOutputStream());
print.println(line);
if("over".equals(line)){
break;
}
//返回的数据包:in
//输入流
InputStream in = socket.getInputStream();
byte[] bs = new byte[1024];
int len = in.read(bs);
String str = new String(bs,0,len);
System.out.println("收到服务端发回数据:"+str);
}
System.out.println("客户端关闭");
socket.close();
}
}
package com.test;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 大写转换服务端
* @author Administrator
*
*/
public class ToUpperServer {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(8877);
Socket socket = ss.accept();
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
while(true){
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line = reader.readLine();
if("over".equals(line)){
break;
}
String ip = socket.getInetAddress().getHostAddress();
System.out.println("客户端发来数据:"+ip+"\n"+line);
line = line.toUpperCase();
out.write(line.getBytes());
}
System.out.println("客户端关闭");
socket.close();
System.out.println("服务端关闭");
ss.close();
}
}
文本上传
package com.test;
import java.io.*;
import java.net.Socket;
/**
* 文本上传客户端
* @author Administrator
*
*/
public class UploadClient {
public static void main(String[] args) throws Exception {
Socket socket = new Socket("127.0.0.1",10003);
System.out.println("客户端开启");
//创建使用默认大小的输入缓冲区的缓冲字符输入流,参数为文件
//BufferedReader从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取
BufferedReader reader = new BufferedReader(new FileReader("E:\\1.txt"));
//将对象的格式表示打印到文本输出流
PrintWriter out = new PrintWriter(socket.getOutputStream());
String line = null;
//readLine()读一行文字
while((line = reader.readLine())!=null){
//打印一个字符串,然后终止行
out.println(line);
}
System.out.println("客户端上传成功!");
reader.close();
out.close();
socket.close();
}
}
package com.test;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 文本上传服务端
* @author Administrator
*
*/
public class UploadServer {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(10003);
System.out.println("服务端开启");
Socket socket = ss.accept();
InputStream in = socket.getInputStream();
//读取
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
//写入
BufferedWriter writer = new BufferedWriter(new FileWriter("E:\\2.txt"));
String line = null;
while((line = reader.readLine())!=null){
writer.write(line);
}
System.out.println("服务端接收成功!");
writer.close();
reader.close();
socket.close();
ss.close();
}
}
上传图片:
package com.test;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* 图片文件上传 客户端
*/
public class UploadClient2 {
public static void main(String[] args) throws Exception {
Socket socket = new Socket("127.0.0.1",10005);
System.out.println("客户端启动");
//读取要上传的文件
InputStream in = new FileInputStream("E:\\1.jpg");
//发送给服务器的socket输出流
OutputStream out = socket.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while((len = in.read(buf))!=-1){
out.write(buf,0,len);
}
System.out.println("客户端上传完成!");
//shutdownOutput:对于TCP套接字,任何先前写入的数据将被发送,随后是TCP的正常连接终止序列
//告诉服务端上传完成,让服务器停止读取
socket.shutdownOutput();
in = socket.getInputStream();
byte[] bufin = new byte[1024];
len = in.read(bufin);
String text = new String(bufin, 0, len);
System.out.println(text);
in.close();
out.close();
socket.close();
}
}
package com.test;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 图片文件上传 服务器
*/
public class UploadServer2 {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(10005);
System.out.println("服务端启动");
Socket socket = ss.accept();
OutputStream out = new FileOutputStream("E:\\server.jpg");
InputStream in = socket.getInputStream();
byte[] buf = new byte[1024];
int len = 0;
while((len = in.read())!=-1) {
out.write(buf, 0, len);
}
out = socket.getOutputStream();
out.write("服务端返回:上传成功!".getBytes());
in.close();
out.close();
socket.close();
ss.close();
}
}
class UploadThread2 implements Runnable{
private Socket socket = null;
private int i = 0;
public UploadThread2(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
InputStream in = socket.getInputStream();
OutputStream out = new FileOutputStream(socket.getInetAddress().getHostAddress()+"_"+(i++)+"_"+".jpg");
int i = -1;
while((i = in.read())!=-1){
out.write(i);
}
in.close();
out.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}