网络编程

(笔记)Linux下网络编程,采用TCP协议实现的C/S架构 TCP/UDP介绍TCP(Transfer Control Protocol)传输控制协议是一种面向连接的协议, 当我们的网络程序使用这个协议的时候,可以保证我们的客户端和服务端的通信是可靠的,安全的,适合于传输大批量数据的情况. UDP(User Datagram Protocol)用户数据报协议是一种非面向连接的协议, 这种协议并不能保证我们的网络程序的通信是可靠的,适合一次传输少量的数据. 阅读详情

1.网络编程

1.1 网络编程三要素

1. 协议
	两个在于网络情况下的计算机数据传递,都需要对应的协议来完成。常见的协议有TCP协议和UDP协议
UDP协议:
    用户数据报协议(User Datagram Protocol)
    UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在接收到数据后,也不会向发送端反馈是否收到数据
    由于使用UDP协议消耗资源小,通信效率高,所以通常用于音频,视频和普通数据的传输
    例如视频会议通常采用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响,但是在使用UDP传输数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议
TCP协议:
    传输控制协议(Transmission Control Protocol)
    TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输,在TCP连接中要明确客户端和服务器端,由客户端向服务器端发出连接请求,每次连接的创建都需要经过三次握手
    三次握手:TCP协议中,在发送数据的准备阶段,客户端与服务器端的三次交互,以保证连接的可靠
      第一次握手:客户端向服务器端发送连接请求,等待服务器确认
      第二次握手:服务器端向客户端回送一个响应,通知客户端接收到了连接请求
      第三次握手:客户端再次向服务器端发送确认消息,确认连接
    完成三次握手,连接建立后,客户端和服务器端就可以开始数据传输了。由于这种面向连接的特性,TCP协议可以保证数据传输的安全,所以应用十分广泛,例如文件上传,下载文件,浏览网页。
      

2. IP地址
	Internet Protocol Address
	当前计算机在网络中的一个地址编号,类似于手机号号码
IP地址有IPv4协议和IPv6协议
IPv4是一个32位的二进制数,
IPv4:是给每个链接在网络上的主机分配一个32bit地址。通常展示效果是a.b.c.d 例如 192.168.1.1,a.b.c.d 各代表0 ~ 255的数字,目前已经消耗殆尽 42亿个。按照TCP/IP协议规定,IP地址用二进制来表示,每个IP地址长32bit,也就是4个字节。例如一个采用二进制形式的IP地址是"11000000 10101000 00000001 01000010",这么长的地址,处理起来很费劲,为了方便使用,IP地址经常被写成十进制的形式,中间使用符号"."分隔不同的字节。于是上面的地址可以表示成"192.168.1.66"。IP地址的这种表示法叫做"点分十进制表示法",这显然比1和0容易记忆得多。
IPv6
	IPv6是能够保证地球上的每一粒沙子都有一个IP地址。
	128位地址长度,16字节一组
	8组 0x0 ~ 0xFFFF
.DOS常用命令:
     ipconfig:查看本机ip地址
     ping IP地址:检查网络是否连通
.特殊IP地址:
	 127.0.0.1:是回送地址,可以代表本机地址,一般用来测试使用

3. 端口号
	端口号是当前应用程序在计算机中的一个编号。可以让计算机明确知道,当前的数据是给予那一个程序使用,或者数据从哪一个程序出现的。
	端口号是一个short类型 0 ~ 65535
	0~1024不能用于自定义端口号使用,特定的系统端口号

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WfRq2ltP-1594732603930)(C:\Users\86182\Pictures\Saved Pictures\网络协议示意图.png)]

1.2 InetAddress

InetAddress:此类表示Internet协议(IP)地址,是SUN公司提供给开发者得IP类

  • 相关方法
方法名说明
InetAddress getLocalhost();获取本机IP地址类对象
InetAddress getByName(String str);根据指定的主机名获取对应的IP地址对象
InetAddress[] getAllByName(String str);获取指定主机名,或者域名对应的所有IP地址类对象
String getHostName();获取此IP地址得主机名
String getHostAddress();返回文本显示中得IP地址字符串
  • 代码演示:
package com.tao;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
 * @Classname TestInetAddress
 * @Description 测试IP类
 * @Date 2020/7/13 14:36
 * @Author Anonymous
 */
public class TestInetAddress {
    public static void main(String[] args) throws UnknownHostException {
        InetAddress localHost = InetAddress.getLocalHost();
        System.out.println(localHost);

        InetAddress byName = InetAddress.getByName("DESKTOP-3KH4ONS");
        System.out.println(byName);

        InetAddress byName1 = InetAddress.getByName("192.168.0.104");
        System.out.println(byName1);
        String hostName = byName1.getHostName();
        String hostAddress = byName1.getHostAddress();
        System.out.println(hostName + "---" + hostAddress);


        InetAddress byName2 = InetAddress.getByName("www.4399.com");
        System.out.println(byName2);

        InetAddress[] allByName = InetAddress.getAllByName("www.jd.com");
        for (InetAddress inetAddress : allByName) {
            System.out.println(inetAddress);
        }


        InetAddress[] allByName1 = InetAddress.getAllByName("www.taobao.com");
        for (InetAddress inetAddress : allByName1) {
            System.out.println(inetAddress);
        }

    }
}
/**
DESKTOP-3KH4ONS/192.168.0.104
DESKTOP-3KH4ONS/192.168.0.104
/192.168.0.104
DESKTOP-3KH4ONS---192.168.0.104
www.4399.com/219.157.114.132
www.jd.com/42.225.97.3
www.taobao.com/42.236.122.9
www.taobao.com/42.236.122.10

1.3 UDP和TCP/IP的区别

UDP
	1. 面向无连接,数据传递不算特别安全
	2. 因为面向无连接,传输速度快
	3. 因为面向无连接,数据传递存在丢包问题
	4. UDP没有客户端和服务器区别,都可以作为发送端和接收端
	UDP协议使用场景
		直播,网络游戏

TCP/IP
	1. 面向连接,数据传递较为安全
	2. 因为面向连接,所有传递速度较慢
	3. 面向连接,数据传递有保障
	4. TCP/IP协议是有明确的服务器和客户端概念
	TCP/IP协议使用场景
		客户端登陆,数据下载,文件传输

2.UDP通信程序

2.1 UDP数据传输方式

User Datagram Protocol 
	数据传递采用数据包方式传递,所有的数据要进行打包操作,并且没有对应的客户端服务器概念,有且只有发送段和接收端
	
Socket 套接字
	数据需要进行传递操作,在数据传递的两台计算机当中必须有对应的Socket。这里采用UDP协议,那么必须有一个UDP协议的Socket
	DatagramSocket();
		创建一个发送端UDP协议Socket对象
	DatagramSocket(int port);
		创建一个接收端UDP协议的Socket对象,这里需要【监听】指定端口
		
发送端数据包的打包方法:
	DatagramPacket DatagramPacket(byte[] buf, int length, InetAddress address, int port);
	buf: 需要传递数据的字节数组
	length:是当前字节数组中数据容量字节数
	address:接收端IP地址对象
	port: 接收端对应的端口号

接收端数据包接收方式
	这里需要准备一个空的数据包
	DatagramPacket DatagramPacket(byte[] buf, int length);
	buf: 字节缓冲数组,通常是1024整数倍
	length: 当前字节缓冲数组的容量

2.2 发送端

流程:
	1. 创建UDP服务器对应的发送端Socket
	2. 准备对应数据包,需要带有指定数据
	3. 发送数据 send
	4. 关闭UDP发送端
package com.tao;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/*
流程:
	1. 创建UDP服务器对应的发送端Socket
	2. 准备对应数据包,需要带有指定数据
	3. 发送数据 send
	4. 关闭UDP发送端
 */
public class SenderDemo1 {
	public static void main(String[] args) throws IOException {
		System.out.println("发送端启动");
		// 创建对应的Socket
		DatagramSocket socket = new DatagramSocket();
		
		// 准备数据包
		byte[] bytes = "今天中午吃蒸羊羔...".getBytes();
		DatagramPacket packet = new DatagramPacket(bytes,  // 字节数组数据
				bytes.length,  // 字节数组数据长度
				InetAddress.getLocalHost(),  // 指定接收端IP地址
				8848); // 8848对应端口号
		
		// 发送数据包
		socket.send(packet);
		
		// 关闭UDP发送端
		socket.close();
	}
}	

2.3 接收端

流程:
	1. 打开UDP服务,并且监听指定端口
	2. 创建新的空数据包
	3. 通过Socket接收数据 
	4. 关闭UDP服务接收端
package com.qfedu.b_udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

/*
流程:
	1. 打开UDP服务,并且监听指定端口
	2. 创建新的空数据包
	3. 通过Socket接收数据 receive
	4. 关闭UDP服务接收端
 */
public class ReceiveDemo1 {
	public static void main(String[] args) throws IOException {
		// 创建Socket监听端口
		DatagramSocket socket = new DatagramSocket(8848);
		
		// 准备空数据包
		byte[] buf = new byte[1024];
		DatagramPacket packet = new DatagramPacket(buf, buf.length);
		
		// 接收数据
		socket.receive(packet);
		
		// 确定接收到的字节长度
		int length = packet.getLength();
        //返回数据缓冲区
        byte[] b = packet.getData();
		
		System.out.println(new String(b, 0, length));
		
		// 关闭socket
		socket.close();
		
	}
}

2.4 UDP通信练习

案例需求:
   UDP发送数据:数据来自键盘录入,直到输入的数据是886,发送数据结束
   UDP接收数据:因为接收端不知道发送端什么时候停止发送,故采用死循环接收
package com.tao;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
/**
 * @Classname Send
 * @Description 发送端
 * @Date 2020/7/13 16:43
 * @Author Anonymous
 */
public class Send {
    public static void main(String[] args) throws IOException {
        //创建发送端的Socket对象
       DatagramSocket datagramSocket = new DatagramSocket();
       //自己封装录入键盘数据
       BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
       String line;
       while ((line = bufferedReader.readLine())!=null){
           //输入的数据是886,停止发送
           if ("886".equals(line)){
               break;
           }
           //创建数据并把数据打包
           byte[] bytes = line.getBytes();
           DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length,InetAddress.getLocalHost(),9999);
           datagramSocket.send(datagramPacket);
       }
       //关闭发送端
        datagramSocket.close();

    }
}


package com.tao;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
 * @Classname Receive
 * @Description 接收端
 * @Date 2020/7/13 16:43
 * @Author Anonymous
 */
public class Receive {
    public static void main(String[] args) throws IOException {
      DatagramSocket datagramSocket = new DatagramSocket(9999);
      while (true){
      	//创建一个数据包用于接收数据
		  byte[] bytes = new byte[1024];
		  DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length);
		  datagramSocket.receive(datagramPacket);
		  //解析数据包并在控制台打印
		  System.out.println(new String(datagramPacket.getData(),0,datagramPacket.getLength()));
	  }

      //因为一直在接收,所以不需要关闭
     // datagramSocket.close();

	}
}

上面的发送端也可以用Scanner:

package com.tao;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
import java.util.Scanner;

/**
 * @Classname Send
 * @Description 发送端
 * @Date 2020/7/13 16:43
 * @Author Anonymous
 */
public class Send {
    public static void main(String[] args) throws IOException {
       DatagramSocket datagramSocket = new DatagramSocket();
        while (true){
        Scanner sc = new Scanner(System.in);
        String next = sc.next();
           if ("886".equals(next)){
               break;
           }
           byte[] bytes = next.getBytes();
           DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length,InetAddress.getLocalHost(),9999);
           datagramSocket.send(datagramPacket);
       }
        datagramSocket.close();
    }
}

3. TCP通信程序

3.1 TCP概述

TCP相对于UDP比较稳定的传输协议,这里存在三次握手,保证连接状态,同时有明确的客户端和服务端之分
	TCP服务中需要服务器端先启动,需要监听指定端口,等待客户端连接。
	客户端主动连接服务器,和服务器连接之后,才可以进行数据交互,服务器不能主动连接客户端的。

TCP操作而言,Java中提供了两个Socket
	1. 服务端Socket 
		java.net.ServerSocket;
		创建对应的ServerScoket开启服务器,等待客户端连接
	2. 客户端Socket
		java.net.Socket
		创建客户端Scoket,并且连接服务器,同时将Socket发送给服务器绑定注册。

3.2 客户端Socket

给客户端提供数据传输的符合TCP/IP要求的Socket对象

构造方法 Constructor
	Socket(String host, int port);
		host是服务器IP地址,port对应服务器程序的端口号
		通过指定的服务器IP地址和端口号,获取TCP连接对象

成员方法 Method	
	InputStream getInputStream();
		获取Socket对象输入字节流,可以从服务器获取对应的数据
		InputStream是一个资源,需要在程序退出是关闭
		Read
	
	OutputStream getOutputStream();
		获取Sokcet对象输出字节流,可以发送数据到服务器
		OutputStream是一个资源,需要在程序退出是关闭
		Write
	
	void close();
		关闭客户端Socket
	
	void shutdownOutput();
		禁止当前Socket发送数据

TCP/IP协议对应的Socket是给予IO流实现的。

3.3 服务器端ServerSocket

在服务端开启Socket服务器
构造方法 Constructor:
	ServerSocket(int port);
		开启ServerSocket服务器,并且明确当前服务端口是谁

成员方法 Method:
	Socket accept();
		监听并且连接,得到一个Socket对象,同时该方法是一个阻塞方法,会处于一个始终
		的监听状态
		返回的是Socket,也就是客户端Socket对象,获取到当前Socket对象,相对于获取到
		客户端连接,同时使用的Socket和客户端一致。

3.4 代码演示

/**
 *案例需求
 *客户端:发送数据,接收服务器端反馈
 *服务器端:收到消息后给出反馈
*/
package com.tcp;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
/**
 * @Classname TestSocket
 * @Description TODO
 * @Date 2020/7/13 21:41
 * @Author Anonymous
 */
public class TestSocket {
    public static void main(String[] args) throws IOException {
        //创建客户端的Socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(),9999);
        //获取输出流,写出数据
        OutputStream outputStream = socket.getOutputStream();
        byte[] bytes = "你好,西南交通大学".getBytes();
        outputStream.write(bytes);


        //接收服务器端反馈
        InputStream inputStream = socket.getInputStream();
        byte[] b = new byte[1024];
        inputStream.read(b);
        System.out.println(new String(b,0,b.length));

        //释放资源
 //       inputStream.close();
 //       outputStream.close();
        socket.close();
    }
}


package com.tcp;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @Classname TestServerSocket
 * @Description TODO
 * @Date 2020/7/13 21:41
 * @Author Anonymous
 */
public class TestServerSocket {
    public static void main(String[] args) throws IOException {
        //创建服务器端的Socket对象
        ServerSocket serverSocket = new ServerSocket(9999);
        //监听客户端连接,返回一个Socket对象
        Socket socket = serverSocket.accept();
        //获取输入流读取数据并打印在控制台上
        InputStream inputStream = socket.getInputStream();
        byte[] bytes = new byte[1024];
        inputStream.read(bytes);
        System.out.println(new String(bytes,0,bytes.length));

        //给出反馈
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("数据已经收到".getBytes());
    }
}

3.5练习

/**
 *案例需求
 *客户端数据来自键盘录入,直到输入的数据是886,发送数据结束
 *服务端:接到数据后在控制台输出
*/
package com.tao;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;

/**
 * @Classname Send1
 * @Description TODO
 * @Date 2020/7/14 11:07
 * @Author Anonymous
 */
public class Send1 {
    public static void main(String[] args) throws IOException {
        //创建客户端Socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(),9999);
        //数据来自键盘录入,直到输入的数据是886,停止发送
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        //封装输出流对象
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

        String line;
        while ((line = br.readLine())!=null){
            if ("886".equals(line)){
                break;
            }
            bw.write(line);
            bw.newLine();
            bw.flush();

        }
        //释放资源
        socket.close();
    }
}


package com.tao;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @Classname Receive1
 * @Description TODO
 * @Date 2020/7/14 11:07
 * @Author Anonymous
 */
public class Receive1 {
    public static void main(String[] args) throws IOException {
        //创建服务器Socket对象
        ServerSocket serverSocket = new ServerSocket(9999);
        //监听客户端的连接,返回一个相应的Socket对象
        Socket socket = serverSocket.accept();
        //获取输入流
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

        String line;
        while ((line = bufferedReader.readLine())!=null){
            System.out.println(line);
        }
        //释放资源
        serverSocket.close();
    }
}

3.6文件上传

3.6.1 文件上传案例分析

TCP通信文件上传案例:
原理:客户端读取本地的文件,把文件上传到服务器,服务器把上传的文件保存到服务器的硬盘上

步骤:
1.客户端使用本地的字节输入流读取要上传的文件
2.客户端使用网络字节输出流,把读取的文件上传到服务器
3.服务器使用网络字节输入流,读取客户端上传的文件
4.服务器使用本地的字节输出流,把读取的文件保存到服务器的硬盘上
5.服务器要使用网络字节输出流,给客户端回写一个"上传成功"
6.客户端使用网络字节输入流,读取服务器回写的数据
7.释放资源
注意:客户端和服务器对硬盘进行读写,需要使用自己创建的字节流对象(本地流)
     客户端和服务器之间进行读写,必须使用Socket中提供的字节流对象(网络流)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E2H144ZL-1594732603931)(C:\Users\86182\Pictures\Saved Pictures\文件上传细节图例.png)]

3.6.2 代码实现

package com.tcp;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
/**
 * @Classname TestFileUploadSocket
 * @Description 文件上传之客户端
 * @Date 2020/7/14 13:42
 * @Author Anonymous
 */
public class TestFileUploadSocket {
    public static void main(String[] args) throws IOException {
        //创建一个本地流用来读取硬盘文件
        InputStream localInputStream = new FileInputStream(new File("E:\\btn.jpg"));
        //创建一个客户端的Socket对象并指定服务器的IP地址和端口号
        Socket socket = new Socket(InetAddress.getLocalHost(),9999);
        //创建一个输出流用于向服务器端写数据
        OutputStream outputStream = socket.getOutputStream();
        //定义一个缓冲区用于往里面读取数据
        byte[] bytes = new byte[1024];
        int len;
        while ((len=localInputStream.read(bytes))!=-1){
            outputStream.write(bytes,0,len);
        }

        /**
         * 解决阻塞问题:
         * void shutdownOutput()
         *   对于TCP套接字,任何以前写入的数据都会被发送,并且后跟TCP的正常连接终止序列
         **/
         socket.shutdownOutput();

        //创建一个网络输入流用来读取服务器端回写的数据
        InputStream internetInputStream = socket.getInputStream();
        byte[] b = new byte[1024];
        int length;
        while ((length=internetInputStream.read(b))!=-1){
            System.out.println(new String(b,0,length));
        }
        //释放资源
        outputStream.close();
        socket.close();
        localInputStream.close();
    }
}


package com.tcp;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;

/**
 * @Classname TestFileUploadServerSocket
 * @Description 文件上传之服务器端
 * @Date 2020/7/14 13:43
 * @Author Anonymous
 */
public class TestFileUploadServerSocket {
    public static void main(String[] args) throws IOException {
        //创建服务器端的Socket对象
        ServerSocket serverSocket = new ServerSocket(9999);

        /*
         让服务器一直处于监听状态(死循环accept方法)
         有一个客户端上传文件,就保存一个文件
         */
        while (true){
            //监听客户端连接,返回一个Socket对象
            Socket socket = serverSocket.accept();
            //获取网络输入流用于读取客户端发送的数据
            InputStream internetInputStream = socket.getInputStream();
            //判断E盘下的文件夹是否存在,不存在则创建一个
            File file = new File("E:\\upload");
            if (!file.exists()){
                file.mkdir();
            }

        /*
           自定义文件的命名规则:防止同名的文件被覆盖
           规则:域名+毫秒值+随机数
         */
            String fileName = "tao" +
                    System.currentTimeMillis() +
                    new Random().nextInt(999999) + ".jpg";

            //创建本地输出流用于写到服务器端的硬盘上
            //OutputStream localOutputStream = new FileOutputStream(file + "\\1.jpg");
            OutputStream localOutputStream = new FileOutputStream(file + "\\" + fileName);
            //定义一个字节缓冲区用于读取数据
            byte[] bytes = new byte[1024];
            int len;
            while ((len=internetInputStream.read(bytes))!=-1){
                localOutputStream.write(bytes,0,len);
            }

            //创建一个网络输出流,当上传成功后给客户端一个反馈
            OutputStream internetOutputStream = socket.getOutputStream();
            byte[] b = "上传成功".getBytes();
            internetOutputStream.write(b);

            //释放资源
            localOutputStream.close();
            internetInputStream.close();
        }
        //服务器不需要再关闭
        //serverSocket.close();
    }
}

阻塞问题分析:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DSNUMtlm-1594732603932)(E:\Java百度网盘解压\Java SE\09网络编程\22.【网络编程】-笔记\resource\04_文件上传案例的阻塞问题.bmp)]

改用多线程代码实现:

package com.tcp;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;


public class TestFileUploadServerSocketThread {
    public static void main(String[] args) throws IOException {
        //1.创建一个服务器ServerSocket对象,和系统要指定的端口号
        ServerSocket server = new ServerSocket(9999);
        //2.使用ServerSocket对象中的方法accept,获取到请求的客户端Socket对象

        /*
            让服务器一直处于监听状态(死循环accept方法)
            有一个客户端上传文件,就保存一个文件
         */
        while(true){
            Socket socket = server.accept();

            /*
                使用多线程技术,提高程序的效率
                有一个客户端上传文件,就开启一个线程,完成文件的上传
             */
            new Thread(new Runnable() {
                //完成文件的上传
                @Override
                public void run() {
                    try {
                        //3.使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
                        InputStream is = socket.getInputStream();
                        //4.判断d:\\upload文件夹是否存在,不存在则创建
                        File file =  new File("E:\\upload");
                        if(!file.exists()){
                            file.mkdirs();
                        }

                    /*
                        自定义一个文件的命名规则:防止同名的文件被覆盖
                        规则:域名+毫秒值+随机数
                     */
                        String fileName = "itcast"+System.currentTimeMillis()+new Random().nextInt(999999)+".jpg";

                        //5.创建一个本地字节输出流FileOutputStream对象,构造方法中绑定要输出的目的地
                        //FileOutputStream fos = new FileOutputStream(file+"\\1.jpg");
                        FileOutputStream fos = new FileOutputStream(file+"\\"+fileName);
                        //6.使用网络字节输入流InputStream对象中的方法read,读取客户端上传的文件


                        int len =0;
                        byte[] bytes = new byte[1024];
                        while((len = is.read(bytes))!=-1){
                            //7.使用本地字节输出流FileOutputStream对象中的方法write,把读取到的文件保存到服务器的硬盘上
                            fos.write(bytes,0,len);
                        }


                        //8.使用Socket对象中的方法getOutputStream,获取到网络字节输出流OutputStream对象
                        //9.使用网络字节输出流OutputStream对象中的方法write,给客户端回写"上传成功"
                        socket.getOutputStream().write("上传成功".getBytes());
                        //10.释放资源(FileOutputStream,Socket,ServerSocket)
                        fos.close();
                        socket.close();
                    }catch (IOException e){
                        System.out.println(e);
                    }
                }
            }).start();


        }

        //服务器就不用关闭
        //server.close();
    }
}



//使用lambda表达式
package com.tcp;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;


public class TestFileUploadServerSocketThread {
    public static void main(String[] args) throws IOException {
        //1.创建一个服务器ServerSocket对象,和系统要指定的端口号
        ServerSocket server = new ServerSocket(9999);
        //2.使用ServerSocket对象中的方法accept,获取到请求的客户端Socket对象

        /*
            让服务器一直处于监听状态(死循环accept方法)
            有一个客户端上传文件,就保存一个文件
         */
        while(true){
            Socket socket = server.accept();
            

            /*
                使用多线程技术,提高程序的效率
                有一个客户端上传文件,就开启一个线程,完成文件的上传
             */
            new Thread(()-> {
                FileOutputStream fos = null;
                //完成文件的上传
                    try {
                        //3.使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
                        InputStream is = socket.getInputStream();
                        //4.判断E:\\upload文件夹是否存在,不存在则创建
                        File file =  new File("E:\\upload");
                        if(!file.exists()){
                            file.mkdirs();
                        }

                    /*
                        自定义一个文件的命名规则:防止同名的文件被覆盖
                        规则:域名+毫秒值+随机数
                     */
                        String fileName = "tao"+System.currentTimeMillis()+new Random().nextInt(999999)+".jpg";

                        //5.创建一个本地字节输出流FileOutputStream对象,构造方法中绑定要输出的目的地
                        //FileOutputStream fos = new FileOutputStream(file+"\\1.jpg");
                        fos = new FileOutputStream(file+"\\"+fileName);
                        //6.使用网络字节输入流InputStream对象中的方法read,读取客户端上传的文件


                        int len =0;
                        byte[] bytes = new byte[1024];
                        while((len = is.read(bytes))!=-1){
                            //7.使用本地字节输出流FileOutputStream对象中的方法write,把读取到的文件保存到服务器的硬盘上
                            fos.write(bytes,0,len);
                        }


                        //8.使用Socket对象中的方法getOutputStream,获取到网络字节输出流OutputStream对象
                        //9.使用网络字节输出流OutputStream对象中的方法write,给客户端回写"上传成功"
                        socket.getOutputStream().write("上传成功".getBytes());
                        //10.释放资源(FileOutputStream,Socket,ServerSocket)
                        
                    }catch (IOException e){
                        System.out.println(e);
                    }finally {
                        try {
                            socket.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        try {
                            fos.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
            }).start();


        }

        //服务器就不用关闭
        //server.close();
    }
}

Lua语言的网络编程 Lua是一种轻量级的、高级的脚本语言,最早由巴西的天主教大学(PUC-Rio)于1993年开发。Lua的设计初衷是作为一种嵌入式语言,易于扩展和与其他语言互操作。Lua的语法简单易懂,支持多种编程范式,包括过程式、命令式和函数式编程。Lua语言因其轻量、灵活的特性,适合用于网络编程。在本文中,我们介绍了Lua语言的基本网络编程知识,包括Socket编程、数据传输协议,以及几个常用的网络库。通过实践案例,演示了如何使用Lua进行HTTP请求和创建Web服务。 阅读详情

相关推荐

kaggle-NeurIPS - Open Polymer Prediction 2025-0.069

本文摘要: 本研究基于多任务学习框架,开发了聚合物物理化学性质预测模型,能够根据SMILES字符串同步预测玻璃化转变温度(Tg)、分数游离体积(FFV)等5种关键性质。针对数据缺失率高、样本不均衡等挑战,采用"先补充后扩充"策略整合多源数据,并融合RDKit分子描述符、ChemBERTa语义特征和自编码器特征构建多维度表征。模型采用硬参数共享架构,结合动态加权损失函数和早停机制,在验证集上表现出色,其中密度预测R²达0.92。研究为聚合物性能的高通量预测提供了有效解决方案,对材料智能设计具有重要参考价值。

2302_78976920的博客 784

TCP通信程序_hehe.employment.11.2

11.5 TCP 通信的概述 两端通信时步骤: 服务端程序,需要事先启动,等待客户端的连接。 客户端主动连接服务器端,连接成功才能通信。服务端不可以主动连接客户端。 在Java中,提供了两个类用于实现TCP通信程序: 客户端: java.net.Socket 类表示。创建 Socket 对象,向服务端发出连接请求,服务端响应请求,两者建立连接开始通信。 服务端: java.net.ServerSocket 类表示。创建 ServerSocket 对象,相当于开启一个服务,并等待客户端的连接。

原来是个傻子,请坐 !!! 349

iverilog+GTKwave使用总结

iverilog是一个开源的硬件描述语言(HDL)仿真工具,用于对硬件描述语言(如Verilog)编写的数字电路进行仿真。它可以将Verilog代码编译为仿真模型,并通过仿真运行来验证设计的正确性。iverilog支持IEEE 1364-2005 Verilog语言标准,并提供了丰富的功能,包括对多种Verilog语言特性的支持、模块化设计、测试平台等。它还可以与其他工具(如GTKWave波形查看器)配合使用,以便进行仿真后的波形查看和分析。

争取早日成为硅农 2万+

Linux的简单的socket网络编程实例

TCP的简单介绍: TCP/IP(TransmissionControl Protocol/InternetProtocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。        TCP/IP协议存在于OS中,网络服务通过OS提供,在OS中增加支持TCP/IP的系统调用——Berkeley套接字,如Socket,Connect,Sen

Chen_dSir的博客 982

VSCode+Keil高效开发STM32:Keil Assistant插件配置全攻略

本文详细介绍了如何通过VSCode的Keil Assistant插件,将Keil MDK的编译调试能力与VSCode的现代编辑体验相结合,打造高效的STM32开发环境。文章涵盖了从环境配置、工程导入、智能提示设置到与STM32CubeMX协同工作的全流程攻略,旨在解决Keil编辑器效率低下的痛点,大幅提升嵌入式开发的编码与项目管理效率。

gold的博客 508

Ceres Solver:从入门到使用

Ceres Solver是谷歌开源的C++非线性优化库,能够解决有约束或无约束条件下的非线性最小二乘问题。2010年之后大量的运用在谷歌的产品开发中,尤其在谷歌开源的cartographer中被大量的使用。 ceres可以在Linux,Windows,macOS,Andrioid,IOS系统进行安装使用,详情可查看下方的官网链接。 Ceres Solver 官网:http://ceres-solver.org/

非晚非晚的博客 1万+

Java网络编程实现

前言 计算机网路实现了多个网络终端的互联,彼此之间能够进行数据交流。而网络应用程序就是在已连接的不同终端设备上运行的程序,这些网络程序相互之间可以进行数据交互。网络程序的数据交互则依赖于TCP/IP协议,在实际应用中TCP网络程序提供可靠的数据通信,而UDP网络程序则不保证数据的可靠性,但是协议简单、传输速度快(比如用在音视频数据传输,它们不需要很高的可靠性,偶尔丢帧是可以忍受的)。 Serv...

dosthing的博客 1万+

C# 原生数字孪生的尝试

本文介绍了使用C#实现数字孪生的基本思路。首先从爱普生官网下载机器人3D模型,然后通过Blender创建并导出带动画的FBX模型。在WPF项目中,使用HelixToolkit.SharpDX等插件加载模型,通过Viewport3DX进行3D渲染。关键点是通过动画控制器接收真实设备信号来驱动模型动画,实现物理实体与虚拟模型的同步。文中提供了完整的代码实现,包括模型导入、动画播放控制等核心功能。该方法为构建数字孪生系统提供了一种可行的技术方案。

qq_33529095的博客 1333

Java网络编程(七):浅谈 Linux 中 Selector 的实现原理

概述 Selector是NIO中实现I/O多路复用的关键类。Selector实现了通过一个线程管理多个Channel,从而管理多个网络连接的目的。 Channel代表这一个网络连接通道,我们可以将Channel注册到Selector中以实现Selector对其的管理。一个Channel可以注册到多个不同的Selector中。 当Channel注册到Selector后会返回...

萝卜代码 801

静态时序分析Static Timing Analysis1——STA概述、标准工艺库、时钟、IO约束的建立

简要介绍STA和标准工艺库内容,对时钟,IO等进行约束的指令介绍,PVT

qq_42135020的博客 7541

DO-297标准详解:IMA系统开发与认证指南

DO-297的前言部分为读者提供了本指南的概述,说明了该标准的编写背景、主要目标、目标受众以及该文件在开发和认证集成模块化航空电子(IMA,Integrated Modular Avionics)系统中的作用。作为现代航空电子架构的重要组成部分,IMA系统大幅度简化了航空电子系统的硬件配置,增加了灵活性并降低了成本。因此,DO-297成为确保IMA系统开发、集成和认证符合适航标准的核心文件。在现代航空领域,系统复杂性逐渐增加,传统上各子系统独立运行的方式已经不适应多任务、多功能的需求。

qq_41854911的博客 1585

【网络编程】网络编程 和 Socket 套接字认识

为什么需要网络编程,什么是网络编程,Socket 套接字的简要认识

bit me的博客 3085

华为OD机试双机位C卷-简单的解压缩算法(C/C++/Py/Java/Js/Go)

华为OD机试(机考)双机位C卷 【简单的解压缩算法】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD真题【简单的解压缩算法】。

qq_45776114的博客 476

网络编程是什么

对于初学者,或者没有接触过网络编程的程序员,会觉得网络编程涉及的知识很高深,很难,其实这是一种误解,当你的语法熟悉以后,其实基本的网络编程现在已经被实现的异常简单了。 网络编程是什么 网络编程的本质是两个设备之间的数据交换,当然,在计算机网络中,设备主要指计算机。数据传递本身没有多大的难度,不就是把一个设备中的数据发送给两外一个设备,然后接受另外一个设备反馈的数据。 现在的网络编程基本上都是基于请求/响应方式的,也就是一个设备发送请求数据给另外一个,然后接收另一个设备的反馈。 在网络编程中,发起连接程序,也

m0_67392661的博客 3859

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Java网络编程1 - 介绍网络编程、网络编程三要素

IP:设备在网络中的地址,是设备在网络中的唯一标识。端口:应用程序在设备中的唯一标识。协议:连接和数据在网络中传输的规则。IP(Internet Protocol):全称“互联网协议地址”,是分配给上网设备的唯一标识。IP域名,简称“域名”。用于在互联网上识别和定位网站的人类可读的名称。举例:因为人们不可能记具体的IP地址,比如192.168.1.100,而是记域名,比如www.baidu.com。是互联网中用于将域名转换为对应IP地址的分布式命名系统。

casually的博客 1277

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

【网络编程】Socket网络编程基础

文章目录网络编程概述Socket与TCP UDPSocket TCP演示报文段协议Mac地址IP、端口、远程服务器IPv4IPv6端口远程服务器 网络编程概述 什么是网络编程 网络编程从大的方面说就是对信息的发送到接收 通过操作相应Api调度计算机硬件资源,并利用传输管道(网线)进行数据交换的过程 更为具体的涉及:网络模型、套接字、数据包 网络模型 – 对应关系 具体细节看一看我的 专栏《计算机...

明月沉江春雾晓 3818

Haskell语言的网络编程

Haskell语言的网络编程通过其强大的类型系统、清晰的语法以及丰富的库使得开发者可以高效地构建各种网络应用,从简单的TCP客户端到功能强大的Web服务。本文介绍了Haskell网络编程的基础知识、常用库、基础示例以及进阶应用。随着Haskell社区的不断发展,网络编程领域的库和框架也在不断地更新与扩展。因此,学习Haskell网络编程不仅能够提升个人的编程技能,也助于应对现代开发中的各种挑战。希望本文能够为对Haskell网络编程感兴趣的开发者提供一些启发与帮助。

2401_90086250的博客 1554

Android 网络编程入门指南

在移动应用开发中,网络编程是一个不可或缺的部分。它允许应用与远程服务器进行数据交换,实现数据的上传和下载。本文将为你提供一个关于Android网络编程的入门指南,帮助你理解基本概念和实现步骤。

Unity打怪升级 2330

Linux网络编程

socket()函数用于创建一个新的套接字,并返回套接字的文件描述符。如果套接字创建失败,函数将返回-1。

cyz322649的博客 1358

【Java网络编程详解】

Java网络编程是开发分布式应用程序的重要技能,它通过套接字(Socket)进行数据传输,支持TCP和UDP协议。本文将介绍Java网络编程的基础知识,包括Socket、ServerSocket、TCP通信、UDP通信、常用类和示例代码。网络编程是指在计算机之间通过网络进行数据传输和通信的编程方式。Java提供了强大的java.net包,封装了底层的网络协议,简化了网络编程。:面向连接,可靠传输,保证数据按序到达,适合文件传输、Web通信等。:面向无连接,不可靠但速度快,适合视频通话、广播消息等。

武帝为此的博客 958

Java网络编程

Java是 Internet 上的语言,它从语言级上提供了对网络应用程序的支持,程序员能够很容易开发常见的网络应用程序。 Java提供的网络类库,可以实现无痛的网络连接,联网的底层细节被隐藏在 Java 的本机安装系统里,由 JVM 进行控制。并且 Java 实现了一个跨平台的网络库,程序员面对的是一个统一的网络编程环境。

HL031125的博客 1110

[网络编程】网络编程的基础使用

在本文中主要讲解了TCP和UDP两个协议之间的区别;同时对UDP网络编程进行了最基础的创建。

Starc_的博客 1262

【python】python进阶——网络编程

Python网络编程指南:从基础到实践 本文系统介绍了Python网络编程的核心知识。首先阐述了网络编程基础概念,包括IP地址、端口和协议等关键要素。重点讲解了Socket编程,详细展示了TCP/UDP Socket的创建、服务器/客户端工作流程及代码实现。

weixin_51924657的博客 1370

网络编程概述

本文系统梳理了网络编程的核心知识点及其在嵌入式领域的应用。主要内容包括: 网络协议栈分层模型(OSI/TCP/IP)和关键协议原理(TCP/UDP/IP) 应用层协议(HTTP/MQTT等)及网络编程模型(I/O多路复用、异步I/O) 嵌入式网络编程的特殊性:资源受限、多通信方式、实时性要求 嵌入式常用技术:轻量级协议栈(lwIP)、物联网协议(MQTT/CoAP)。

eatbaozi的博客 1245
上一篇: Java常用API之Date和Calendar类
下一篇: 学数组看这篇文章就够了
Hello World......
博客等级 码龄9年 89粉丝 76原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值