在正式讲解之前,我们先来看看一些基本基础知识,只有知道这些知识,才能更好的学习好网络编程,这些基础知识如下:
1.为什么需要网络编程
简单来说,需要在两台不同的计算机之间进行数据传递,所以需要网络编程。
2.常见的两种协议
TCP/IP:TCP 是传输控制协议的缩写,它保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称 TCP / IP。
UDP:UDP 是用户数据报协议的缩写,一个无连接的协议。提供了应用程序之间要发送的数据的数据包。
Socket类:
1.服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。
2.服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。
3.服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。
4.Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。
5.在服务器端,accept() 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket。
3. 举例说明客户端与服务端的区别:
客户端:例如手机APP 浏览器 桌面qq
服务器端:是用来存储/处理数据
4. URL:统一的资源定位
例如一个浏览器中的地址栏: http://www.baidu.com/search?code=android
- http/https : 传输协议
- www.baidu.com"域名,表示一台网络中的电脑
- IPv4 IPv6 地址:唯一标识一台网络中的电脑
- 32位:四个部分每个是8个字节《------》www.baidu.com
- DNS服务器:域名解析, 功能是将诸如www.baidu.com解析为对应的ip地址
- serach:对应的后台程序文件
- ?需要传递的参数、
- code = android code 之服务器端规定的字段
- &如果有多个参数是用&符号来连接
5.IP地址和端口号
上面我们说过了IP地址,这里说一下端口号的作用:
从图可以看出,虽然指定了IP地址,但是还是不能我完成通信,所以,端口号就是解决图中的问题的。
利用网络实现的如下功能:
- 1.固定内容发送
- 2.服务器端手动输入内容发送
- 3.向服务器端传送图片
- 4.实现群聊功能
1,固定内容发送
客户端:
class Client {
public static void main(String[] args) throws IOException {
//1.创建用于通信的socket
// 指明和谁通信:ip地址 端口号
Socket socket = new Socket("192.168.43.32",8989);
// 接收服务器端的数据
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//读取服务器端发来的数据
String line = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
// 客户端向服务器端发送数据
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println("你好啊");
socket.shutdownInput();
}
}
服务器端:
class Server{
public static void main(String[] args) throws IOException {
//1.创建服务器端的serversocket
ServerSocket ss = new ServerSocket(8989);
//2.获取连接的客户端的socket
Socket clientSocket = ss.accept();
//3.向客户端发送数据
//BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
PrintStream ps = new PrintStream(clientSocket.getOutputStream());
ps.println("登录成功");
//输出完毕
clientSocket.shutdownInput();
//4.接收客户端发来的数据
BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String line = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
}
}
解析:简单来说,实现网络编程,需要做的工作有以下几点:
客户端:
- 创建用于通信的socket,指明IP地址,端口号,明确知道将要和谁通信。Socket socket= new Socket("192.168.43.32",9090);
- 网络编程中,接收服务器端的数据。
- 向服务器端传送数据。
以字符为例接收服务器端的数据的例子如下格式:
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//读取服务器端发来的数据
String line = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
想服务器端发送数据的例子格式如下:
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write("你好啊");
或者:
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println("你好啊");
服务器端:
首先第一步:创建ServerSocket
ServerSocket serverSocket = new ServerSocket(9090)
第二步:获取连接服务器端的客户端的socket
Socket socket = serverSocket.accept();
第三步:向客户端发送数据:
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
bw.write("登录成功");
或者:
PrintStream ps = new PrintStream(clientSocket.getOutputStream());
ps.println("登录成功");
第四步:从客户端接收数据:
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
while ((line = br.readLine())!=null){
System.out.println(line);
}
2,手动输入
客户端:
class MyClient{
public static void main(String[]args){
Socket socket= null;
try {
socket= new Socket("192.168.43.32",9090); //链接服务器端de Socket
//接受服务端的数据
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
while ((line = br.readLine())!=null){
System.out.println(line);
}
//发送从键盘的数据给服务器端
BufferedReader Bw = new BufferedReader(new InputStreamReader(System.in));
//获取服务端的输出流
PrintStream ps = new PrintStream(socket.getOutputStream());
String line1 = null;
while ((line1 = Bw.readLine())!=null){
ps.println(line);
}
} catch (IOException e) {
System.out.print("网络出错,请重新登陆");
}finally {
//关闭连接
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
这段代码与固定发送给的代码相比,只有一小点不同,创建socket那些都是一样的,不一样的就是,要从输入端输入然后再发送给服务器端,传输对象,因为这样,所以多了判断的语句,其他的都一模一样。
发送从键盘的数据给服务器端
BufferedReader Bw = new BufferedReader(new InputStreamReader(System.in));
服务器端:
class MyServer{
public static void main(String[]args){
//创建ServerSocket
//写在try的圆括号里面,是因为它会自动关闭
try( ServerSocket serverSocket = new ServerSocket(9090);) {
//监听连接
Socket socket = serverSocket.accept();
//从终端接收数据
BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
//获取想客户端输出数据的输出流
PrintStream ps = new PrintStream(socket.getOutputStream());
String line= null;
while ((line = keyin.readLine())!=null){
ps.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
同样这里也是,只是多了从输入端作为发送对象,其他的都是一样的逻辑。
3.向服务器端传送图片
客户端:
class Client{
public static void main(String[] args) throws IOException {
//连接服务器 获取socket
Socket socket = new Socket("192.168.43.32",8080);
//创建服务器端对应的输入流 用于接收服务器端发来的数据
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println(br.readLine());
//向服务器端发送文件(图片)
//1.将文件写入到内存里
String path = "C:\\Users\\Administrator\\Desktop\\01.PNG";
FileInputStream fis = new FileInputStream(path); //从path中读取
//2.创建字节流 outputStream
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
byte[] buf = new byte[1024];
int len = -1;
while ((len = fis.read(buf)) != -1){
bos.write(buf,0,len);
}
socket.shutdownOutput();
}
}
向服务器端发送图片的步骤:
- 1.获取需要发送的图片的地址
- 2.在当前文件中保存需要发送的图片
- 3.以字节流的形式发送图片
获取需要发送的图片的地址
String path = "C:\\Users\\Administrator\\Desktop\\01.PNG";
在当前文件中保存需要发送的图片
FileInputStream fis = new FileInputStream(path);
以字节流的形式发送图片
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
byte[] buf = new byte[1024];
int len = -1;
while ((len = fis.read(buf)) != -1){
bos.write(buf,0,len);
}
服务器端:
class Server{
public static void main(String[] args) throws IOException {
//创建服务器端的ServerSoket
ServerSocket ss = new ServerSocket(8080);
//监听客户端连接
//当有客户端来连接这个服务器 就可以得到对应的socket
//当没有客户端来连接 服务器一直在这里等待
Socket socket = ss.accept();
//创建客户端对应的输出流 用于向这个客户端发送数据
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println("连接成功 可以发数据了!");
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
String path = "C:\\Users\\Administrator\\Desktop\\java\\java\\java1\\src\\main\\java\\day12\\radio\\02.PNG";
FileOutputStream fos = new FileOutputStream(path);
byte[] buf = new byte[1024];
int len = -1;
while((len = bis.read(buf)) != -1){
fos.write(buf,0,len);
}
}
}
4,实现群聊
客户端
class Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("192.168.43.32", 9999);
// 用一个子线程处理服务器端的数据
// new Thread(new ClientThread(socket)).start();
// 主线程处理终端输入,发送给服务器端
BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
PrintStream ps = new PrintStream(socket.getOutputStream());
String line = null;
while ((line = keyin.readLine()) != null) {
ps.println(line);
}
}
}
创建一个子线程,处理客户端接收来自服务器端的数据
class ClientThread implements Runnable {
private Socket socket;
public ClientThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
BufferedReader br = null;
try {
//获取服务端的输入流对象
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
System.out.print(line);
}
} catch (IOException e) {
System.out.print("网络错误,请重新登录");
System.exit(-1);
} finally {
try {
if (br != null){
br.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
System.out.print("网络出错,请重新登陆");
System.exit(-1);
}
}
}
}
服务器端:
class Server{
//保存每一个socket对象
public static ArrayList<Socket> sockets = new ArrayList<>();
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9994);
//不停的等待客户端来连接
while (true) {
Socket socket = serverSocket.accept();
sockets.add(socket);
new ServerThread(socket).start();
}
}
}
继承Thread 创建子线程
class ServerThread extends Thread {
private Socket socket;
public ServerThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
while ((line = br.readLine())!=null){
for(Socket s :Server.sockets){
PrintStream ps = new PrintStream(s.getOutputStream());
ps.println(line);
}
}
} catch (IOException e) {
e.printStackTrace();
System.out.print("网络异常,请重新登陆");
System.exit(-1);
} finally {
try {
if (br != null)
br.close();
if (socket != null)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
解析:实现这个群聊的功能,最重要的就是想到,怎样做到是群聊的效果,这里运用的是一个socket数组,一个统一的服务器端,是群聊消息的时候就遍历socket数组,给每个元素都发相同的消息。
public static ArrayList<Socket> sockets = new ArrayList<>();
遍历:
for(Socket s :Server.sockets){
PrintStream ps = new PrintStream(s.getOutputStream());
ps.println(line);
总结:对于之前没有学过网络编程的来说,这是一个新的知识点。刚开始学,还不能很好的与多线程,文件的操作等合理的集合起来。还需要大量的练习代码。
网友评论