
-
把分布在不同地理区域的计算机与专门的外部设备用通讯线相互连接成的规模大的、功能强的网络系统,
从而让众多的计算机和一方便的互相传递信息。
- 资源共享
- 信息传输与集中处理
- 负载均衡与分布处理,等等。
- 要使计算机连成的网络能够互通信息,需要对数据传输速率、传输代码、代码结构、传输控制步骤、出错控制等 制定一组标准,这一组共同遵守的通信标准就是网络通信协议,不同的计算机之间必须使用相同的通讯协议 才能进行通信。
- TCP/IP: 网络控制协议/因特网互联协议, 又叫网络通讯协议,这个协议是Internet最基本的协议、Internet国际互 联网络的基础,简单地说,就是由网络层的IP协议和传输层的TCP协议组成的。
- IP地址: 网络中每台计算机的一个标识号
- 端口号(port): 端口号的范围:065535之间,01023之间的端口数是用于一些知名的网络服务和应用
- 网络传输所经历的七层协议
- 主要的程序开发有两种结构
- C/S (客户端/服务器), 比如: qq, 微信。
- B/S(浏览器/服务器), 比如: chrome, fireFox
- C/S程序主要采用以下两种协议开发
- TCP: 传输控制协议, 采用三次握手的方式,确保准确的连接 *** 作。
- UDP:(User Datagram Protocol)数据报协议,发送数据报,例如:广播, 只关乎发送,不关乎是否接收
-
TCP 是一个可靠的协议, 面向连接的协议
-
实现TCP程序, 需要编写服务器端和客户端, Java API 为我们提供了Java.net 包, 为实现网络应用程序提供的类。
-
为实现应用程序,需要知道套接字
- 套接字(Socket): Socket 是网络驱动提供给应用程序编程的接口和一种机制。
- 套接字对应着网络驱动, 网络驱动对应着网卡, 网卡对应着网线
-
需要用到以下两种接口
- ServerSocket : 实现服务器的套接字
- Socket: 实现客户端的套接字
-
数据实际接收的过程
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class ServiceSocketDemo {
public static void main(String[] args) {
try {
// 创建服务端套接字
// param1: 此服务器要绑定的端口号
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("创建服务器成功, 等待客户端的到来。。。");
// 如果有客户端连接, 则会解阻塞, 并返回一个socket
Socket cli_socket = serverSocket.accept();
// 获取输入流
BufferedReader br = new BufferedReader(new InputStreamReader(cli_socket.getInputStream()));
System.out.println("等待客户端发送数据");
String con = br.readLine();
System.out.println("cli:" + con);
// 获取输出流, 向客户端返回数据
PrintStream ps = new PrintStream(new BufferedOutputStream(cli_socket.getOutputStream()));
ps.println(con);
ps.flush();
// 关闭流
ps.close();
br.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
2) 客户端
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class SocketDemo {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
try {
// 创建套接字
// param1: 要连接的ip
// param2: 服务器段所用的端口号
Socket socket = new Socket("localhost", 8080);
System.out.println("服务器连接成功。。。");
// 获取输出流
PrintStream ps = new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
ps.println(input.next());
ps.flush();
// 获取输入流
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 接收服务器端发送过来的数据, 如果服务器端没有发送数据过来,则会阻塞
System.out.println("等待服务器端发送数据。。。");
System.out.println("server:" + br.readLine());
// 关闭流
ps.close();
br.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
2、多个客户端与一个服务器端进行通讯
- 客户端不变
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ServerSocketDemo2 {
// 创建一个线程池(含三个线程)
public static ExecutorService es = Executors.newFixedThreadPool(3);
public static void main(String[] args) throws IOException {
// 创建服务器
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("服务器创建成功!, 等待客户端的到来。。");
while(true) {
Socket cli_socket = serverSocket.accept();
System.out.println("ip号为" + cli_socket.getInetAddress() + "键入了连接");
// 去执行向相应的任务
es.execute(new UserService(cli_socket));
}
}
}
class UserService implements Runnable {
private Socket s = null;
public UserService(Socket socket) {
this.s = socket;
}
@Override
public void run() {
try {
// 创建一个输入流,获取用户发送过来的内容
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
System.out.println(s.getInetAddress() + ": " + br.readLine());
// 关闭
br.close();
System.out.println("ip:" + s.getInetAddress() + "结束连接");
}catch (IOException e) {
e.printStackTrace();
}
}
}
3、多个客户端之间进行通信
1) 客户端
package top2.grace.ChatDemo;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Client {
private static String name;
public static Scanner input = new Scanner(System.in);
public static ObjectOutputStream oos;
public static ObjectInputStream ois;
public static boolean flag = true;
// 创建线程池
public static ExecutorService es = Executors.newFixedThreadPool(2);
public static void main(String[] args) {
// 创建socket对象
try {
Socket socket = new Socket("localhost", 8000);
// 获取输入输出流
oos = new ObjectOutputStream(socket.getOutputStream());
ois = new ObjectInputStream(socket.getInputStream());
System.out.print("请输入登录用户名:");
name = input.next();
Message msg = new Message(name, "", MessageType.LOGIN_TYPE, "");
oos.writeObject(msg);
System.out.println("正在登录。。。");
msg = (Message)ois.readObject();
System.out.println("登录成功!");
System.out.println(msg.getData());
// 一个线程进行接收信息
es.execute(new AcceptMsg());
// 一个线程进行发送信息
es.execute(new SendMsg());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
static class AcceptMsg implements Runnable {
@Override
public void run() {
while(flag) {
try {
Message msg = (Message)ois.readObject();
System.out.println("["+msg.getFromName()+"]:"+msg.getData());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
static class SendMsg implements Runnable {
@Override
public void run() {
while(flag) {
System.out.println("请输入对方的名字:");
String toname = input.next();
System.out.println("请输入发送的信息:");
String data = input.next();
try {
Message msg = new Message(name, toName, MessageType.SEND_TYPE, data);
// 发送信息
oos.writeObject(msg);
System.out.println("消息已发送");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
2) 服务器端
package top2.grace.ChatDemo;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.ServerSocket;
import java.util.Vector;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
public class Service {
// 创建一个线程池, 含有3个线程, 三个线程只能三个人进行聊天
public static final ExecutorService es = Executors.newFixedThreadPool(3);
// 创建一个集合用于存储客户端的socket对象
public static final Vector serviceList = new Vector<>();
public static void main(String[] args) throws IOException {
// 创建服务器, 并绑定8080端口
ServerSocket serverSocket = new ServerSocket(8000);
System.out.println("服务器启动成功等待客户端的加入。。。");
// 接收用户的请求, 并将请求,交给子线程
while(true) {
Socket socket = serverSocket.accept();
System.out.println(socket.getInetAddress().getHostAddress() + "加入了连接");
es.execute(new ServiceUser(socket, serviceList));
}
}
}
class ServiceUser implements Runnable {
private String name; // 当前的用名
private Socket s; // 当前所有连接用户的socket
private Vector serviceList; // 所有在在线的用户
private ObjectInputStream ois; // 当前输入流
private ObjectOutputStream oos; // 当前输出流
public ServiceUser (Socket s, Vector serviceList) {
this.s = s;
this.serviceList = serviceList;
}
@Override
public void run() {
try {
// 获取当前socket的输入流与输出流
ois = new ObjectInputStream(s.getInputStream());
oos = new ObjectOutputStream(s.getOutputStream());
while (true) {
// 获取当前socket 所携带的数据包
Message current_msg = (Message)ois.readObject();
name = current_msg.getFromName();
// 判断消息类型
switch(current_msg.getMessageType()) {
case MessageType.SEND_TYPE:
int size = serviceList.size();
System.out.println("size:" + size);
for (int i = 0; i < size; i++) {
ServiceUser serviceUser = serviceList.get(i);
if (current_msg.getToName().equals(serviceUser.name) && this != serviceUser) {
serviceUser.oos.writeObject(current_msg);
break;
}
}
break;
case MessageType.LOGIN_TYPE:
// 将当前socket对象添加到集合中
serviceList.add(this);
// 返回信息
current_msg.setData("欢迎" + current_msg.getFromName());
oos.writeObject(current_msg);
break;
}
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
3)定义的Message类 和 MessageType类
// Message类
package top2.grace.ChatDemo;
import sun.plugin2.message.Serializer;
import java.io.Serializable;
// 数据包类, 且这个类可以被序列化
public class Message implements Serializable {
private String fromName; // 发送方的名字
private String toName; // 接收方的名字
private int messageType; // 信息类型
private String data; // 发送的数据
public Message() {
}
public Message(String fromName, String toName, int messageType, String data) {
this.fromName = fromName;
this.toname = toName;
this.messageType = messageType;
this.data = data;
}
public String getFromName() {
return fromName;
}
public String getToName() {
return toName;
}
public int getMessageType() {
return messageType;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
// MessageType类
package top2.grace.ChatDemo;
public class MessageType {
public static final int LOGIN_TYPE = 1;
public static final int SEND_TYPE = 2;
}
3、UDP 套接字使用
1) 服务器端
package top.grace.UdpDemo;
import java.io.IOException;
import java.net.*;
public class Service {
public static void main(String[] args) {
// 构建数据
String info = "我是村东头的张三";
byte[] data = info.getBytes();
// 构建数据包
try {
DatagramPacket dp = new DatagramPacket(
data, // 要发送的字节数据
0, // 从字节数组中哪个位置开始
data.length, // 要发送数据的长度
InetAddress.getByName("localhost"), // 目标地址
8000 // 目标端口
);
// 创建数据报套接字
// 这端口是本程序的
DatagramSocket ds = new DatagramSocket(9000);
ds.send(dp);
System.out.println("发送完毕!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
2) 客户端
package top.grace.UdpDemo;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class client {
public static void main(String[] args) {
// 构建一个空的数据包, 用于接收接收
byte[] data = new byte[1024];
DatagramPacket dp = new DatagramPacket(data, data.length);
// 构建一个数据报Socket
try {
// 此端口为本程序端口
DatagramSocket ds = new DatagramSocket(8000);
System.out.println("正在接收数据。。。");
ds.receive(dp);
// dp.getData() 表示接收到的数据
// dp.getLength() 表示接收到的实际数据的长度
System.out.println(new String(dp.getData(), 0, dp.getLength()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 注意:要先开启客户端,进行等待接收,在开启服务器进行发送
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)