概述
1.如何建立两个节点(电脑)之间的网络连接?
2.如何向另外一个节点(电脑)发送信息?
3.如何从外部节点(电脑)接收一个请求并给预响应?
4.如何利用网络协议(TCP,UDP)?
网络通信协议七层模型
OSI(Open System Interconnection)
TCP/IP协议
TCP/IP协议(定义了电子设备(比如计算机)如何连入因特网,以及数据如何在它们之间传输的标准)。
IP : ip地址唯一 确定与哪台电脑通信
四个字节 每个字节用 “ . ”分割 256的四次方个ip地址 每一位的范围: 0~255
域名 英文符号替换IP 为方便记忆
映射: www.baidu.com 绑定一个IP ,访问百度根据域名
可通过域名解析器实现域名转换ip
端口:端口号 0~65535个 确定与这台电脑的哪个程序通信
- 网络是什么?
网络是信息传输、接收、共享的虚拟平台。
网络是用物理链路将各个孤立的工作站或主机相连在一起,组成数据链路,从而达到资源共享和通信的目的。
网络通信是两台或多台电脑之间能进行连接、信息交互。
广域网(外网)、局域网(内网)
TCP 协议通信
TCP协议是一种面向连接的、可靠的、基于字节流的传输层通信协议。
面向连接:发送数据前三次握手建立连接
如:打电话 必须双方连接后才能打
可靠性:有序到达,重发机制
如何建立连接? 三次握手
第一次握手: 确定客户端发送能力
第二次握手:确定服务器端接收能力,发送能力
第三次握手:确定客户端接收能力
使用TCP协议实现通信,需要使用流式套接字。
即客户端采用socket,而服务器端采用ServerSocket来完成通信的方式。
- 什么是socket?
套接字 相当于插座,通过它发送给接收数据(电流)。
套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。网络套接字是IP地址与端口的组合。
当连接建立时,服务器会创建一个 Socket 对象。客户端和服务器现在可以通过对 Socket 对象的写入和读取(字节流)来进行通信。
ServerSocket :等待客户端的连接
ServerSocket(int port)创建未绑定的服务器套接字
accept() 监听端口 等待客户端的连接 一旦有客户端的连接,得到与客户端一对一的 Socket
Sokect(网络地址,端口号) 构造方法
- 流式套接字 TCP 面向连接
- 数据报式套接字 UDP通信
- 原始式套接字 IP直接访问
基本流程
服务器端
创建一个ServerSocket
调用accept()等待客户端连接
得到客户端的Socket对象,调用getInputStream()、getOutputStream()得到输入输出流
输入流接收数据,输出流发送数据
close() 关闭资源
客户端
创建Socket,请求服务器地址,端口,与服务器进行连接
调用getInputStream()、getOutputStream()得到输入输出流
输出流接收数据,输入流发生数据
close()
启动顺序:先启动服务器,再启动客户端
数据流:
服务器端
package Send;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8888);
Socket client = serverSocket.accept();//阻塞
System.out.println("有客户端连接");
//网络流
InputStream in = client.getInputStream();
OutputStream out = client.getOutputStream();
BufferedReader br= null;
BufferedWriter bw = null;
br = new BufferedReader(new InputStreamReader(in));
bw = new BufferedWriter(new OutputStreamWriter(out));
//接收数据
String line = br.readLine();//阻塞方法 读到行结尾 换行符
System.out.println("客户端说:"+line);
//发送数据
bw.write("你好客户端!我是服务器!");
bw.newLine();//换行符
bw.flush();//刷新缓冲区
//关闭资源
bw.close();
br.close();
serverSocket.close();
}
}
客户端
package Send;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",8888);
//发送数据
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
BufferedReader br= null;
BufferedWriter bw = null;
br = new BufferedReader(new InputStreamReader(in));
bw = new BufferedWriter(new OutputStreamWriter(out));
//发送数据
Scanner input = new Scanner(System.in);
bw.write(input.next());
// bw.write("你好服务器!我是客户端!");
bw.newLine();//换行符
bw.flush();//刷新缓冲区
//接收数据
String line = br.readLine();//阻塞方法 读到行结尾 换行符
System.out.println("服务端说:"+line);
//关闭资源
bw.close();
br.close();
socket.close();
}
}
实现多个客户端连接
package Send;
import java.io.*;
import java.net.Socket;
public class Server2Thread extends Thread{
private Socket client;
//client 属性赋值: 1. set方法 2. 构造方法
public Server2Thread(String name,Socket client) {
super(name);
this.client = client;
}
@Override
public void run() {
BufferedReader br = null;
BufferedWriter bw = null;
try {
InputStream in = client.getInputStream();
OutputStream out = client.getOutputStream();
br = new BufferedReader(new InputStreamReader(in));
bw = new BufferedWriter(new OutputStreamWriter(out));
//接收数据
String line = br .readLine();
System.out.println(Thread.currentThread().getName()+"说:"+ line);
System.out.println();
//发送数据
bw.write("你好 客户端");
bw.newLine();//换行符
bw.flush();//刷新缓存区
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
//关闭资源
if (bw != null) bw.close();
if (br != null) br.close();
if (client != null) client.close();
}catch (IOException e){
}
}
}
}
package Send;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server2 {//一个服务器允许连接多个客户端
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8888);
int i =1;
while (true){
Socket client = serverSocket.accept();//阻塞
System.out.println("有客户端连接");
//有一个客户端连接,创建一个线程与该客户端连接
Server2Thread server2Thread = new Server2Thread("客户端"+i,client);
//启动线程
server2Thread.start();
i++;
}
}
}
UDP协议通信
UDP是一个 面向无连接,不可靠的传输层协议。
数据包套接字 面向无连接 类似于 :发短信 管你接不接收
DatagramSocket 发送或接收数据包的套接字,不维护连接状态,不产生输入输出流
DatagramPacket 数据包 封装了数据、数据长度
DatagramPacket(byte[] buf, int length)
构造一个DatagramPacket
用于接收长度的数据包length
。DatagramPacket(byte[] buf, int length, InetAddress address, int port)
构造用于发送长度的分组的数据报包length
指定主机上到指定的端口号。
package UDPTest;
import java.io.IOException;
import java.net.*;
public class Client {
public static void main(String[] args) {
//随机绑定端口
try {
//创建一个用于发送接收的socket
DatagramSocket datagramSocket = new DatagramSocket();
//发送数据包
String str = "出任务出任务";
byte[] content = str.getBytes();
try {
//第三个参数,ip地址封装的对象 类型InetAddress,是接受方的地址
// 第四个参数,对方的端口号
DatagramPacket dp1 = new DatagramPacket(content, content.length, InetAddress.getLocalHost(),7777);
//发送
datagramSocket.send(dp1);
//接收
byte[] replay = new byte[1024];
DatagramPacket dp2 = new DatagramPacket(replay, replay.length);
datagramSocket.receive(dp2);
String msg = new String(replay,0,dp2.getLength());
System.out.println("我是client1,收到消息:"+msg);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} catch (SocketException e) {
e.printStackTrace();
}
}
}
package UDPTest;
import java.io.IOException;
import java.net.*;
public class Client2 {
public static void main(String[] args) {
//随机绑定端口
try {
DatagramSocket datagramSocket = new DatagramSocket(7777);
try {
//接收
byte[] replay = new byte[1024];
DatagramPacket dp2 = new DatagramPacket(replay, replay.length);
datagramSocket.receive(dp2);
String msg = new String(replay,0,replay.length);
System.out.println("我是client2,接收到消息:"+msg);
//发送
String str = "马上马上";
byte[] content = str.getBytes();
//获取对方ip和端口
// dp2.getPort();//本机端口
// dp2.getAddress().getHostName();//获取本机地址
// InetSocketAddress address = (InetSocketAddress) dp2.getSocketAddress(); //获取远程地址
// DatagramPacket dp1 = new DatagramPacket(content, content.length,address);
InetAddress ia = dp2.getAddress();
int port = dp2.getPort();
DatagramPacket dp1 = new DatagramPacket(content, content.length,ia,port);
datagramSocket.send(dp1);
datagramSocket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} catch (SocketException e) {
e.printStackTrace();
}
}
}
利用网络协议(TCP,UDP)
-
某公司想组建本公司的客服聊天系统,用于客户与客服人员的点对点的对话,当客户连接到客服服务器时, 客户(客户端)就可以向客服人员(服务器端)进行咨询
发送消息的线程
package Send;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;
public class SendThread extends Thread{
private Socket socket;
private boolean flag = true;
Scanner input = new Scanner(System.in);
public SendThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
while (flag){
send(input.next());
}
}
//发送
public void send(String str){
OutputStream out = null;
BufferedWriter bw = null;
try {
out = socket.getOutputStream();
bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write(str);
bw.newLine();
bw.flush();
} catch (IOException e) {
flag = false;
CloseUtil.close(bw,socket);
}
}
}
接收消息的线程
package Send;
import java.io.*;
import java.net.Socket;
public class ReceiveThread extends Thread{
private Socket socket;
private boolean flag = true;
public ReceiveThread(String name,Socket socket) {
super(name);
this.socket = socket;
}
@Override
public void run() {
while (flag){
String receive = receive();
System.out.println(receive);
}
}
public String receive() {
InputStream in = null;
BufferedReader br =null;
try {
in = socket.getInputStream();
br =new BufferedReader(new InputStreamReader(in));
String line = br.readLine();
return this.getName()+"说:"+line;
} catch (IOException e) {
flag = false;
CloseUtil.close(br,socket);
}
return null;
}
}
关闭资源的工具类
package Send;
import java.io.Closeable;
public class CloseUtil {
public static void close(Closeable... closeables){ //可变参数
if (closeables != null && closeables.length > 0){
if (closeables != null){
closeables.clone();
}
}
}
}
客户端
package Send;
import java.io.IOException;
import java.net.Socket;
public class Client3 {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",8888);
new SendThread(socket).start();
new ReceiveThread("服务器",socket).start();
}
}
服务端线程
package Send;
import java.net.Socket;
public class ServerThread3 extends Thread{
private Socket client;
public ServerThread3(String name,Socket client) {
super(name);
this.client = client;
}
@Override
public void run() {
//创建发送线程 写
new SendThread(client).start();
//创建接收线程 读
new ReceiveThread(this.getName(),client).start();
}
}
服务端
package Send;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
//用户端和客服端之间需要进行对话
//需要实现一次发送多条消息,同时也可以接受多条消息 通过true设置死循环 能够一直读写
public class Server3 {//点对点 缺点:一对一 一个服务器面对多个客户端 可以接收多个客户端信息,但发送不了给多个不知道发给谁(客人接收不到)
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8888);
int i =1;
while (true){
Socket client = serverSocket.accept();//阻塞
System.out.println("有客户端连接");
//有一个客户端连接,创建一个线程与该客户端连接
ServerThread3 serverThread3 = new ServerThread3("客户端"+i,client);
//启动线程
serverThread3.start();
i++;
}
}
}
-
聊天室2.0 多对多
优化服务器线程代码 实现服务器接收客户端的消息,再将消息写出给其他客户端
package Chat;
import java.io.*;
import java.net.Socket;
import java.util.List;
public class ServerThread4 extends Thread{
private Socket socket;
public ServerThread4(String name, Socket socket) {
super(name);
this.socket = socket;
}
@Override
public void run() {
//先读后发 先执行括号内
while (true){
sendOther(receive());
}
}
public String receive(){
InputStream in = null;
BufferedReader br =null;
try {
in = socket.getInputStream();
br =new BufferedReader(new InputStreamReader(in));
String line = br.readLine();
return this.getName()+"说"+line;
} catch (IOException e) {
CloseUtil.close(br,socket);
}
return "";
}
//发送 转发送给其他人
public void sendOther(String str){
List<Socket> socketList = Server4.socketList;
for (Socket client : socketList){
//排除自己
if (client != socket){
send(str,client);
}
}
}
private void send(String str, Socket client) {
OutputStream out = null;
BufferedWriter bw = null;
try {
out = client.getOutputStream();
bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write(str);
bw.newLine();
bw.flush();
} catch (IOException e) {
CloseUtil.close(bw,client);
}
}
}
-
在线阅读小说
服务器
客户端: 显示菜单(输入)
功能:
-
上传小说
客户端 | 服务器 |
---|---|
连接服务器,创建Socket | 接收客户端连接 |
接收提示,打印 输入 发送小说名 | 发送 “请输入要上传的小说名” |
使用本地缓冲输入流,读取客户端硬盘上传文件 循环读:读一行,通过网络IO输出流发给服务器 | 接收小说名 保存小说名 集合 |
服务器循环读取客户端的数据 创建本地输出流 保存到硬盘 追加模式 | |
小说上传完成 客户端发送“exit” | 服务器接收“exit” 退出循环 |
关闭资源 |
-
在线阅读
客户端 | 服务器 |
---|---|
连接服务器,创建Socket 发送在线阅读指令 2 | 接收客户端连接 |
接收服务器发送的小说列表 并打印 | 发送小说名列表 (字符串 或对象流 序列化 持久化 SerialVersionUID 序列化常量 ObjectOutputStream:对对象进行序列化 |
选择需要阅读的小说序号 发送给服务器 | 接收客户端要阅读的小说序号,通过序号找到对应小说 创建本地输入流 读取对应的小说(100行) 循环读 循环写 发送给客户端 |
接收服务器的发送小说内容 在控制台打印 | |
关闭资源 |
上传路径:原文件夹——客户端——服务器——目标文件夹
前100行 用while循环 k++ 到100行就发送exit 客户端接收到exit就停止打印
客户端
package readBook;
import java.io.*;
import java.net.Socket;
import java.util.List;
import java.util.Scanner;
public class Client {
Scanner input = new Scanner(System.in);
SendUtil sendUtil = new SendUtil();
public static void main(String[] args) {
while (true){
new Client().showMenu();
}
}
public void showMenu(){
System.out.println("欢迎访问xxxx小说网站");
System.out.println("t1.上传小说");
System.out.println("t2.在线阅读");
System.out.println("t3.退出");
System.out.println("请选择:");
int choose = input.nextInt();
switch (choose){
case 1:
//上传小说
upload();
break;
case 2:
//在线阅读
readOnline();
break;
case 3:
System.out.println("感谢使用");
System.exit(1);
default:
showMenu();
}
}
private void readOnline() {
Socket socket =null;
BufferedReader br = null;
BufferedWriter bw = null;
try {
socket = new Socket("127.0.0.1",8888);
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//发送上传的指令
sendUtil.sendWrite(bw,"2");
String nameList = br.readLine();
if (nameList.equals("没有书籍!")){
System.out.println("请去上传书籍");
showMenu();
}else {
System.out.println(nameList);
System.out.println("请选择需要阅读的小说序号:");
sendUtil.sendWrite(bw,input.next());
String content =null;
while (!(content=br.readLine()).equals("exit")){
System.out.println(content);
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
CloseUtil.close(br,bw,socket);
}
showMenu();
}
//上传小说
private void upload() {
//连接服务器
Socket socket =null;
BufferedReader br = null;
BufferedWriter bw = null;
//本地输入流
BufferedReader br2= null;
try {
socket = new Socket("127.0.0.1",8888);
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//发送上传的指令
sendUtil.sendWrite(bw,"1");
//接收服务器信息
String line = br.readLine();
System.out.println(line);
//输入小说名
String name = input.next();
//发送小说名
/* bw.write(name);
bw.newLine();
bw.flush();*/
sendUtil.sendWrite(bw,name);
// 使用本地输入流 读取客户端的硬盘上文件
br2 = new BufferedReader(new FileReader("D:\PracticalTrainning3\homework\8.24\book\"+name+".txt"));
//循环读取
String line2 = null;
while ((line2 = br2.readLine()) != null){//读到文件末尾
//把读到的行发送给服务器
sendUtil.sendWrite(bw,line2);
}
//小说上传完成 发送exit 告诉服务器已退出
sendUtil.sendWrite(bw,"exit");
} catch (IOException e) {
e.printStackTrace();
}finally {
CloseUtil.close(br2,bw,br,socket);
}
showMenu();//回到菜单
}
/* public void sendWrite(BufferedWriter bw,String str) throws IOException {
bw.write(str);
bw.newLine();
bw.flush();
}*/
}
服务器端
package readBook;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Server {
private static List<String > nameList = new ArrayList<>();
public static void main(String[] args) {
BufferedReader br = null;
BufferedWriter bw = null;
try {
//开启服务器
ServerSocket serverSocket = new ServerSocket(8888);
while (true){
Socket accept = serverSocket.accept();
InputStream in = accept.getInputStream();
OutputStream out = accept.getOutputStream();
br = new BufferedReader(new InputStreamReader(in));
bw = new BufferedWriter(new OutputStreamWriter(out));
//读取指令
String flag = br.readLine();
switch (flag){
case "1":
//处理上传
doUpload(accept);
break;
case "2":
//处理在线阅读
doReadOnline(accept);
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void doReadOnline(Socket accept) throws IOException {
BufferedReader br = null;
BufferedWriter bw = null;
br = new BufferedReader(new InputStreamReader(accept.getInputStream()));
bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
File file = new File("D:\PracticalTrainning3\homework\8.24\book\cloud");
File[] files = file.listFiles();
System.out.println("可阅读的书有:");
for (File file1 : files) {
nameList.add(file1.getName());
}
StringBuffer sb = new StringBuffer();
if (nameList.isEmpty()){
sb.append("没有书籍!");
SendUtil.sendWrite(bw,String.valueOf(sb));
}else {
for (int i = 0; i < nameList.size(); i++) {
sb.append(i+1).append(".").append(nameList.get(i));
}
System.out.println(sb);
SendUtil.sendWrite(bw,sb.toString());
}
int num = Integer.valueOf(br.readLine());
String name = "";
for (int i = 0; i < nameList.size(); i++) {
if ((i+1) == num){//判断序号
name = nameList.get(i);
}
}
File file2 = new File(file +"\"+name);
BufferedReader br2 = null;
br2 = new BufferedReader(new FileReader(file2));
String ContentLine = "";
int k =0;
while ((ContentLine = br2.readLine())!= null){
if (k==100){//读一百行
SendUtil.sendWrite(bw,"exit");
break;
}
SendUtil.sendWrite(bw,ContentLine);
k++;
}
/* String content = br2.readLine();
SendUtil.sendWrite(bw,content);
SendUtil.sendWrite(bw,"exit");*/
System.out.println("完成在线阅读");
//关闭资源
nameList.clear();
CloseUtil.close(br2,br,bw,accept);
}
//处理上传
private static void doUpload(Socket accept) throws IOException {
BufferedReader br = null;
BufferedWriter bw = null;
//本地输出流
BufferedWriter bw2 = null;
br = new BufferedReader(new InputStreamReader(accept.getInputStream()));
bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
// System.out.println("请输入要上传的小说名");
//发送小说名
SendUtil.sendWrite(bw,"请输入要上传的小说名");
String name = br.readLine();
// nameList.add(name);
//创建本地输出流
//先判断文件是否存在
File file = new File("D:\PracticalTrainning3\homework\8.24\book\cloud");
if (!file.exists()){
file.mkdirs();
}
bw2 = new BufferedWriter(new FileWriter(file +"\"+ name + ".txt",true));//是否追加 不覆盖 true
//循环接收客户端上传的内容 写入到文件
String line = null;
while (!((line = br.readLine()).equals("exit"))){
SendUtil.sendWrite(bw2,line);
}
System.out.println("上传完成!");
//关闭资源
CloseUtil.close(bw2,bw,br,accept);
}
}
封装写的工具类
package readBook;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.List;
//发送工具类
public class SendUtil {
public static void sendWrite(BufferedWriter bw, String str) throws IOException {
bw.write(str);
bw.newLine();
bw.flush();
}
}
最后
以上就是无心戒指为你收集整理的网络通信的实现网络通信协议七层模型TCP/IP协议TCP 协议通信UDP协议通信的全部内容,希望文章能够帮你解决网络通信的实现网络通信协议七层模型TCP/IP协议TCP 协议通信UDP协议通信所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复