Java基础(四)——泛型、IO流、网络编程

第13章 泛型

13.1 泛型的概述

泛型:参数化类型

类型形参:< T >,< E >,< K>,< V>,< U>,< R>。。。。

类型实参:必须是引用数据类型,不能是基本数据类型

​ < String>,< Integer>,< Student>,<ArrayList< String>>。。。

13.2 形式一:泛型类与泛型接口

1、声明语法格式:

【修饰符】 class 类名/接口<类型形参列表>{
    
}

【修饰符】 class 类名/接口<类型形参1 extends 父类上限>{
    
}
【修饰符】 class 类名/接口<类型形参1 extends 父类上限 & 父接口上限>{
    
}

在类名或接口名后面声明的泛型形参类型,可以在当前类或接口中使用,用作声明成员变量、方法的形参、方法的返回值。

但是不能用于静态成员

2、使用语法格式

在(1)创建泛型类、泛型接口的对象时,为泛型形参指定具体类型

​ (2)在继承泛型类或实现泛型接口时,为泛型形参指定具体类型

示例代码

ArrayList<String> list = new ArrayList<String>();

ArrayList<String> list = new ArrayList<>();//JDK1.7之后可以省略

class MyStringArrayList extends ArrayList<String>{
    
}

class Employee implements Comparable<Employee>{
    public int compareTo(Employee e){
        
    }
}

Arrays.sort(数组,  new  Comparator<泛型实参>(){
    public int compare(泛型实参类型  o1, 泛型实参类型  o2){
        
    }
});

3、泛型如果没有指定,会被擦除,按照最左边的上限处理,如果没有指定上限,按照Object处理

13.3 形式二:泛型方法

1、声明的语法格式

【修饰符】 <泛型形参列表>  返回值类型  方法名(【数据形参列表】)【throws 异常列表】{}
【修饰符】 <泛型形参 extends 父类上限 & 父接口上限>  返回值类型  方法名(【数据形参列表】)【throws 异常列表】{}

(1)在方法返回值类型前面声明的泛型形参类型,只能在当前方法中使用,用于表示形参的类型或返回值类型,或方法局部变量的类型,和别的方法无关。

(2)泛型方法可以是静态方法,也可以是非静态方法

2、 使用

当调用方法,会根据具体的数据的实参的类型,来确定泛型实参的类型。

13.4 通配符?

(1)?:代表任意引用数据类型

(2)? extends 上限:代表上限本身或它的子类

(3)? super 下限:代表下限本身或它的父类

例如:

ArrayList<?>:表示可以接受任意类型

ArrayList<?> list = new ArrayList<String>();
ArrayList<?> list = new ArrayList<Integer>();
ArrayList<?> list = new ArrayList<Animal>();

ArrayList<? extends 上限>:

ArrayList<? extends Person> list = new ArrayList<Person>();
ArrayList<? extends Person> list = new ArrayList<Animal>();//Animal不行,因为Animal是父类
ArrayList<? extends Person> list = new ArrayList<Student>();
ArrayList<? extends Person> list = new ArrayList<Dog>();//Dog也不行

ArrayList<? super 下限>:

ArrayList<? super Person> list = new ArrayList<Person>();
ArrayList<? super Person> list = new ArrayList<Animal>();
ArrayList<? super Person> list = new ArrayList<Student>();//Student,因为Student是子类
ArrayList<? super Person> list = new ArrayList<Dog>();//Dog也不行

ArrayList<?>:不能添加元素,除了null

ArrayList<? extends 上限>:不能添加元素,除了null

ArrayList<? super 下限>:可以添加下限或下限子类的对象

13.5 Collections工具类

java.util.Collections:工具类,操作集合

(1)public static boolean addAll(Collection<? super T> c, T… elements)

添加elements的几个对象到c集合中。T是elements对象的类型,要求Collection集合的元素类型必须是T或T的父类

(2)public static int binarySearch(List<? extends Comparable<? super T>> list,T key)

在list集合中用二分查找key的下标,如果存在返回的是合理的下标,如果不存在返回的是一个负数下标

T是元素的类型,

<? extends Comparable<? super T>>,要求集合的元素必须实现Comparable接口 <? super T>,在实现Comparable接口,可以指定Comparable<类型实参>为T或T的父类。 (3)public static boolean disjoint(Collection<?> c1, Collection<?> c2)

判断c1和c2没有交集就为true

(4)public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)

求coll集合中最大元素

<T extends Object & Comparable<? super T>>:要求T或T的父类实现Comparable接口

因为找最大值需要比较大小

(5)public static <T extends Comparable<? super T>> void sort(List list) 给list集合排序

<T extends Comparable<? super T>>:要求T或T的父类实现Comparable接口

(6)public static Collection synchronizedCollection(Collection c)

以synchronizedXX开头的方法,表示把某种非线程安全集合转为一个线程安全的集合。

(7)public static List unmodifiableList(List<? extends T> list)

以unmodifiableXx开头的方法,表示返回一个“只读”的集合。

第14章 IO流

14.1 java.io.File类

它是文件和目录路径名的抽象描述。

API:

(1)getName():获取文件或目录的名称

(2)getPath():获取文件或目录的路径

(3)getAbsolutePath():获取文件或目录的绝对路径

(4) getCanonicalPath():获取文件或目录的规范路径

(5)long length():获取文件的长度,单位字节

(6)long lastModified():最后修改时间,单位毫秒

(7)String getParent():获取上级或父目录

​ File getParentFile():获取上级或父目录

(8)isFile():判断是否是文件,当且仅当是文件并且是存在的,才会true

(9)isDirectory():判断是否是目录,当且仅当是目录并且存在的,才会true

(10)exists():是否存在

(11)isHidden():是否隐藏

(12)canWrite():是否可写

(13)canRead():是否可读

(14)String[] list():获取下一级

​ File[] listFiles():获取下一级

​ File[] listFiles(FileFilter f):获取下一级,但是会过滤掉一下文件和目录

(15)createNewFile():创建文件

​ createTempFile(String prefix, String suffix)

(16)mkdir():创建一级目录,如果父目录不存在,就失败,但是不报异常

​ mkdirs():创建多级目录

(17)delete():删除文件或空目录

(18)renameTo(File f):重命名文件或目录

14.2 IO流的四大抽象基类

1、四大超类

(1)InputStream:字节输入流

(2)OutputStream:字节输出流

(3)Reader:字符输入流

(4)Writer:字符输出流

2、分类

(1)按照方向分:输入流和输出流

(2)按照处理的方式不同:字节流和字符流

字符流只能处理纯文本的数据(使用范围很窄)

(3)按照角色不同:节点流和处理流

处理流是建立在节点流的基础上的,处理流需要包装一个节点流的对象。

处理流也可以包装另外一个处理流。

其实JDK中IO体系是用到了一个装饰者设计模式

3、API

(1)InputStream:

int read():一次读取一个字节,返回的是本次读取的字节的值,如果流末尾返回-1

int read(byte[] data):一次读取多个字节,读取的数据存储到data字节数组中,最多读取data.length个字节,返回的是实际本次读取的字节的个数,如果流末尾返回-1。从data[0]开始存储。

int read(byte[] data,int offset, int len):一次读取多个字节,读取的数据存储到data字节数组中,最多读取len个字节,返回的是实际本次读取的字节的个数,如果流末尾返回-1。从data[offset]开始存储。

void close():关闭

(2)OutputStream:

void write(int data):一次写一个字节

void write(byte[] data):一次写整个字节数组

void write(byte[] data, int offset, int len):一次字节数组的一部分,从[offset]开始,一共len个

void close():关闭

void flush():刷新

(3)Reader:

int read():一次读取一个字符,返回的是本次读取的字符的Unicode值,如果流末尾返回-1

int read(char[] data):一次读取多个字符,读取的数据存储到data字符数组中,最多读取data.length个字符,返回的是实际本次读取的字符的个数,如果流末尾返回-1。从data[0]开始存储。

int read(char[] data,int offset, int len):一次读取多个字符,读取的数据存储到data字符数组中,最多读取len个字符,返回的是实际本次读取的字符的个数,如果流末尾返回-1。从data[offset]开始存储。

void close():关闭

(4)Writer

void write(int data):一次写一个字符

void write(char[] data):一次写整个字符数组

void write(char[] data, int offset, int len):一次字符数组的一部分,从[offset]开始,一共len个

void write(String str):一次写整个字符串

void write(String str, int offset, int count):一次写字符串的一部分,从[offset]开始,一共count个

void close():关闭

void flush():刷新

14.3 文件IO流

1、类型

FileInputStream:文件字节输入流,可以读取任意类型的文件

FileOutputStream:文件字节输出流,可以把字节数据输出到任意类型的文件

FileReader:文件字符输入流,只能读取纯文本的文件。按照平台默认的字符编码进行解码。

FileWriter:文件字符输出流,只能把字符数据输出到纯文本文件。按照平台默认的字符编码进行编码。

2、读写文件的代码

示例代码:

public void copy(File src, File dest)throws IOException{
    //选择IO流
    FileInputStream fis = new FileInputStream(src);
    FileOutputStream fos = new FileOutputStream(dest);
    
    //读写
    byte[] data = new byte[1024];
    while(true){
        int len = fis.read(data);
        if(len==-1){
            break;
        }
        fos.write(data,0,len);
    }
    
    //关闭
     fis.close();
    fos.close();
}

14.4 缓冲IO流

1、分为

BufferedInputStream:字节输入缓冲流,给InputStream系列IO流增加缓冲效果
BufferedOutputStream:字节输出缓冲流,给OutputStream系列IO流增加缓冲效果
BufferedReader:字符输入缓冲流,给Reader系列IO流增加缓冲效果

String readLine():按行读取

BufferedWriter:字符输出缓冲流,给Writer系列IO流增加缓冲效果

void newLine():输出换行符

在这里插入图片描述

2、默认的缓冲区的大小是8192 = 1024 * 8(字节/字符)

3、可以给读写的过程提高效率

不仅仅是可以给文件IO流增加缓冲效果,可以给任意符合对应类型的IO流增加缓冲效果。

示例代码:

	public void copyBuffer(File src, File dest)throws IOException{
	    //选择IO流
	    FileInputStream fis = new FileInputStream(src);
	    FileOutputStream fos = new FileOutputStream(dest);
	    
	    //BufferedInputStream只能给FileInputStream增加缓冲效果,读的过程加快了
	    BufferedInputStream bis = new BufferedInputStream(fis);//fis在里面,bis在外面,fis比喻成内衣,bis比喻成外套
	    
	    //BufferedOutputStream只能FileOutputStream增加缓冲效果,写的过程加快了
	    BufferedOutputStream bos = new BufferedOutputStream(fos);
	    
	    //数据流向:src-->fis-->bis(从fis先缓冲到bis)-->data-->bos(从data缓冲到bos中)-->fos-->dest
	    
	    //读写
	    byte[] data = new byte[1024];
	    while(true){
	        int len = bis.read(data);
	        if(len==-1){
	            break;
	        }
	        bos.write(data,0,len);
	    }
	    
	    //关闭
	    //关闭比喻成脱衣服
	    bos.close();
        fos.close();
        
	    bis.close();//先脱外套,再脱内衣
	    fis.close();	    
	}

14.5 编码与解码的IO流(转换流)

1、编码:OutputStreamWriter

​ 可以把字符流转为字节流输出,并且在转换的过程中,可以指定字符编码。

2、解码:InputStreamReader

​ 可以把字节输入流转为字符输入流,并且在转换的过程中,可以指定字符编码。

3、示例代码:解码(文件是GBK,当前平台是UTF-8)

	@Test
	public void test4()throws IOException{
		//因为这里想要用在程序中按照“指定”的编码方式进行解码,而不是按照平台“默认的”编码方式进行解码
		//所以,我这里仍然用FileInputStream字节流,把文件编码后的数据,原样读取
		//从文件到FileInputStream fis内存的过程中,先不解码
		//因为如果选择FileReader,从文件到FileReader的过程中,就已经按照平台“默认的”编码方式解码好了,我们无法控制
		
		FileInputStream fis = new FileInputStream("d:/File类概述.txt");
		//我要使用InputStreamReader,把FileInputStream转为字符流
//		InputStreamReader isr = new InputStreamReader(fis);//如果没有指定,还是按照默认的编码方式
		InputStreamReader isr = new InputStreamReader(fis,"GBK");//如果指定,就按照指定的编码方式解码
		
		//文件-->fis(字节流)-->解码-->isr(字符流)-->br ->读取的是字符
		//字符流,要么按照char[]读取,要么可以用BufferedReader包装按行读取
		BufferedReader br = new BufferedReader(isr);
		String line;
		while((line = br.readLine()) !=null){
			System.out.println(line);
		}
		
		br.close();
		isr.close();
		fis.close();
	}

4、示例代码:编码(文件是GBK,当前平台是UTF-8)

	@Test
	public void test3()throws IOException{
		String hua = "File类可以使用文件路径字符串来创建File实例";
		
		//因为想要用在程序中进行编码,所以这里选用FileOutputStream
		FileOutputStream fos = new FileOutputStream("d:/File类概述.txt",true);
		
		//这里xx,想要直接操作字符串,那么必须是字符流,而fos是字节流,无法直接操作字符串
//		xx.write("\r\n");
//		xx.write(hua);
		
		//数据流向:内存 --> osw (字符流)-->在写入fos过程中进行编码-->fos(字节流)-->文件
		
		OutputStreamWriter osw = new OutputStreamWriter(fos,"GBK");
		osw.write("\r\n");
		osw.write(hua);
		
		osw.close();
		fos.close();
	}

14.6 数据IO流

1、类型

DataInputStream:允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。
DataOutputStream:允许应用程序以适当方式将基本 Java 数据类型写入输出流中。

它俩必须配对使用

读的顺序要与写的顺序一致

2、API

DataOutputStreamDataInputStream
writeInt(xx):输出int类型整数int readInt()
writeDouble(xx):输出double类型double readDouble()
writeBoolean(xx)boolean readBoolean()
writeLong(xx)long readLong()
writeChar(xx)char readChar()
writeByte(xx)byte readByte()
writeShort(xx)short readShort()
writeFloat(xx)float readFloat()
writeUTF(String str):输出字符串的String readUTF()

14.7 对象IO流

1、类型

ObjectOutputStream:对象序列化,输出对象,把对象转为字节序列输出

ObjectInputStream:对象反序列化,读取对象,把字节序列重构成Java对象

2、API

ObjectOutputStream:writeObject(对象)

ObjectInputStream:Object readObject()

3、序列化需要注意哪些内容?

(1)所有要序列化的对象的类型都必须实现java.io.Serializable接口

如果对象的属性类型也是引用数据类型,那么也要实现java.io.Serializable接口

(2)希望类的修改对象反序列化不产生影响,那么我们最后能够增加一个序列化版本ID

private static final long serialVersionUID = 1L;

(3)如果有些属性不想要序列化,可以加transient

(4)如果某个属性前面有static修饰,也不参与序列化

4、除了Serializable接口之外,还可以实现java.io.Externalizable接口,但是要求重写:

void readExternal(ObjectInput in)
void writeExternal(ObjectOutput out)

关于哪些属性序列化和反序列化,由程序员自己定。

14.8 其他的IO流相关内容

1、如果要实现按行读取,可选择什么类型?

BufferedReader:String readLine()

Scanner:String nextLine()

2、如果要按行输出,可以选择什么类型?

(1)自己处理\r\n

(2)BufferedWriter:newLine()

(3)PrintStream和PrintWriter:println()

14.9 JDK1.7之后引入新try…catch

语法格式:

try(需要关闭的资源对象的声明){
    业务逻辑代码
}catch(异常类型 e){
    处理异常代码
}catch(异常类型 e){
    处理异常代码
}
....

它没有finally,也不需要程序员去关闭资源对象,无论是否发生异常,都会关闭资源对象

示例代码:

	@Test
	public void test03() {
		//从d:/1.txt(GBK)文件中,读取内容,写到项目根目录下1.txt(UTF-8)文件中
		try(
			FileInputStream fis = new FileInputStream("d:/1.txt");
			InputStreamReader isr = new InputStreamReader(fis,"GBK");
			BufferedReader br = new BufferedReader(isr);
			
			FileOutputStream fos = new FileOutputStream("1.txt");
			OutputStreamWriter osw = new OutputStreamWriter(fos,"UTF-8");
			BufferedWriter bw = new BufferedWriter(osw);
		){
			String str;
			while((str = br.readLine()) != null){
				bw.write(str);
				bw.newLine();
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

第十五章 网络编程

为了更好的理解:web(服务器端和客户端的通信)、数据库(服务器端和客户端的数据传输)等原理。

15.1 主机IP

在程序中表示:

(1)值的表示

IPV4:32位整数,8位一组,用.分割,例如:192.168.11.45

​ 每个8位的范围[0,255]

IPV6:128位整数表示,16位一组,用:分割,例如:X:X:X:X:X:X:X:X

​ 每个16位用十六进制值表示

(2)对象表示:InetAddress

此类表示互联网协议 (IP) 地址,它有两个子类Inet4Address和Inet6Address,分别对应IPV4和IPV6。InetAddress类没有提供公共的构造器,而是提供了如下几个静态方法来获取InetAddress实例。

  • public static InetAddress getLocalHost()
  • public static InetAddress getByAddress(byte[] addr)
  • public static InetAddress getByName(String host)

InetAddress提供了如下几个常用的方法:

  • public String getHostAddress():返回 IP 地址字符串(以文本表现形式)。
  • public String getHostName():获取此 IP 地址的主机名
  • public String getCanonicalHostName():获取此 IP 地址的完全限定域名
  • public boolean isReachable(int timeout):测试是否可以达到该地址。

15.2 端口号

范围:[0,65535]

常见的端口号:

​ tomcat/JBoss:8080

​ http:80

​ mysql:3306

​ oracle:1521

​ sql server:1433

15.3 网络协议

在这里插入图片描述

  • 应用层:网络服务与最终用户的一个接口。协议有:HTTP、FTP、SMTP、DNS、TELNET、HTTPS、POP3等等。
  • 表示层:数据的表示、安全、压缩。格式有:JPEG、ASCll、DECOIC、加密格式等。
  • 会话层:建立、管理、终止会话。对应主机进程,指本地主机与远程主机正在进行的会话
  • 传输层:定义传输数据的协议端口号,以及流控和差错校验。协议有:TCP、UDP。
  • 网络层:进行逻辑地址寻址,实现不同网络之间的路径选择。协议有:ICMP、IGMP、IP(IPV4 IPV6)、ARP、RARP。
  • 数据链路层:建立逻辑连接、进行硬件地址寻址、差错校验等功能。将比特组合成字节进而组合成帧,用MAC地址访问介质,错误发现但不能纠正。
  • 物理层:建立、维护、断开物理连接。

而IP协议是一种非常重要的协议。IP(internet protocal)又称为互联网协议。IP的责任就是把数据从源传送到目的地。它在源地址和目的地址之间传送一种称之为数据包的东西,它还提供对数据大小的重新组装功能,以适应不同网络对包大小的要求。经常与IP协议放在一起的还有TCP(Transmission Control Protocol)协议,即传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议。而通常我们说的TCP/IP协议,其实是指TCP/IP协议族,因为该协议家族的两个最核心协议:TCP(传输控制协议)和IP(网际协议),为该家族中最早通过的标准,所以简称为TCP/IP协议。

TCP:Transmission Control Protocol 传输控制协议
(1)面向连接的:连接之前有三次握手,断开时四次挥手

以下为拟人比喻

在这里插入图片描述

(2)可靠的
(3)基于字节流
(4)可以传输大量数据的
UDP:User Datagram Protocol 用户数据报协议
(1)非面向连接的
(2)不可靠的
(3)基于数据报的
(4)数据量大小有限制的64K

15.4 Socket编程

Socket:套接字,代表网络通信的一端,负责和网卡驱动程序沟通的对象。

在这里插入图片描述

分为:
(1)流套接字:ServerSocket和Socket
(2)数据报套接字:DatagramSocket

ServerSocket的常用构造方法和其他方法:

  • ServerSocket(int port) :指定在某个端口号监听客户端的连接和通信
  • Socket accept() :监听和接收客户端的连接
  • void close() :关闭

Socket类的常用构造方法:

  • public Socket(InetAddress address,int port):创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
  • public Socket(String host,int port):创建一个流套接字并将其连接到指定主机上的指定端口号。

Socket类的常用方法:

  • public InputStream getInputStream():返回此套接字的输入流,可以用于接收消息

  • public OutputStream getOutputStream():返回此套接字的输出流,可以用于发送消息

  • public InetAddress getInetAddress():此套接字连接到的远程 IP 地址;如果套接字是未连接的,则返回 null。

  • public void close():关闭此套接字。套接字被关闭后,便不可在以后的网络连接中使用(即无法重新连接或重新绑定)。需要创建新的套接字对象。 关闭此套接字也将会关闭该套接字的 InputStream 和 OutputStream。

  • public void shutdownInput():如果在套接字上调用 shutdownInput() 后从套接字输入流读取内容,则流将返回 EOF(文件结束符)。 即不能在从此套接字的输入流中接收任何数据。

  • public void shutdownOutput():禁用此套接字的输出流。对于 TCP 套接字,任何以前写入的数据都将被发送,并且后跟 TCP 的正常连接终止序列。 如果在套接字上调用 shutdownOutput() 后写入套接字输出流,则该流将抛出 IOException。 即不能通过此套接字的输出流发送任何数据。

注意:先后调用Socket的shutdownInput()和shutdownOutput()方法,仅仅关闭了输入流和输出流,并不等于调用Socket的close()方法。在通信结束后,仍然要调用Scoket的close()方法,因为只有该方法才会释放Socket占用的资源,比如占用的本地端口号等。

DatagramSocket:

  • DatagramPacket(byte[] buf, int length)
  • DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)

15.5 代码示例

15.5.1 TCP协议编程示例一

一个客户端连接服务器,连接成功后,服务器给客户端发送“欢迎你登录"

package com.atguigu.test10;

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

/*
 * TCP:面向连接,可靠的,基于字节流的
 * 		服务器:等待被连接的过程
 * 
 * ServerSocket:只负责接受和建立连接,不负责数据的传输
 * Socket:负责数据的传输
 * 
 * 步骤:
 * 1、开启服务器
 * 	  指定服务器监听的端口号
 * 2、等待客户端并接受客户端的连接
 * 
 * 3、接受/发送数据
 * 发送方:输出流
 * 接受方:输入流
 * 
 * 4、断开连接
 * 
 * 5、关闭服务器
 */
public class TestServer {
	public static void main(String[] args) throws IOException {
		//1、开启服务器:网卡驱动就监听9999端口号的数据
		ServerSocket server = new ServerSocket(9999);
		
		//2、等待客户端并接受客户端的连接
		Socket socket = server.accept();//这句代码执行一次,就接受一个客户端连接
		System.out.println("一个客户端连接成功!");
		//3、例如:发送数据
		//发送:欢迎你登录
		//字节流,输出流  OutputStream
		//(1)获取输出流
		OutputStream out = socket.getOutputStream();
		//(2)发送数据
		out.write("欢迎你登录".getBytes());
		
		//4、断开连接
		socket.close();
		
		//5、关闭服务器
		server.close();
	}
}

package com.atguigu.test10;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.UnknownHostException;

/*
 * TCP:
 * 	 客户端,主动连接服务器
 * 
 * Socket(InetAddress address, int port) 
 * Socket(String host, int port)
 * 
 * 步骤:
 * 1、连接服务器
 * Socket socket = new Socket("192.168.30.142",9999);
 * 
 * 2、发送或接受数据
 * 
 * 3、断开连接
 */
public class TestClient {
	public static void main(String[] args) throws UnknownHostException, IOException {
//		1、连接服务器
		Socket socket = new Socket("192.168.30.142",9999);
		
		//2、例如:接受数据
		//字节流,输入流,InputStream
		InputStream in = socket.getInputStream();
		byte[] data = new byte[1024];
		int len;
		while((len = in.read(data)) != -1){
			System.out.println(new String(data,0,len));
		}
		
		//3、断开
		socket.close();
	}
}

15.5.2 TCP协议编程示例二

一个客户端连接服务器,连接成功后,客户端给服务器先传一个“你好”,服务器给客户端返回“欢迎你登录"

package com.atguigu.test11;

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

public class TestServer {
	public static void main(String[] args) throws IOException {
		//1、开启服务器:网卡驱动就监听9999端口号的数据
		ServerSocket server = new ServerSocket(9999);
		
		//2、等待客户端并接受客户端的连接
		Socket socket = server.accept();//这句代码执行一次,就接受一个客户端连接
		System.out.println("一个客户端连接成功!");
		
		//3、接受数据
		InputStream in = socket.getInputStream();
		byte[] data = new byte[1024];
		int len;
		System.out.println("服务器收到:");
		while((len = in.read(data)) != -1){
			System.out.println(new String(data,0,len));
		}
		
		//4、例如:发送数据
		//发送:欢迎你登录
		//字节流,输出流  OutputStream
		//(1)获取输出流
		OutputStream out = socket.getOutputStream();
		//(2)发送数据
		out.write("欢迎你登录".getBytes());
		
		//4、断开连接
		socket.close();
		
		//5、关闭服务器
		server.close();
	}
}

package com.atguigu.test11;

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

public class TestClient {
	public static void main(String[] args) throws UnknownHostException, IOException {
//		1、连接服务器
		Socket socket = new Socket("192.168.30.142",9999);
		
		//2、例如:发送你好
		OutputStream out = socket.getOutputStream();
		out.write("你好".getBytes());
//		out.close();//错误的,如果调用out.close()会导致socket的close()
		//如果仅仅表示不发送了,还要接收,那么选择半关闭,只关闭输出通道
		socket.shutdownOutput();
		
		//3、例如:接受数据
		//字节流,输入流,InputStream
		System.out.println("客户端收到:");
		InputStream in = socket.getInputStream();
		byte[] data = new byte[1024];
		int len;
		while((len = in.read(data)) != -1){
			System.out.println(new String(data,0,len));
		}
		
		//3、断开
		socket.close();
	}
}

15.5.3 TCP协议编程示例三

一个客户端连接服务器,连接成功后:

(1)客户端从键盘输入词语,给服务器发送,直到bye为止;

(2)服务器每次手动词语,反转词语 ,然后返回给客户端,直到接收到bye为止

package com.atguigu.test12;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;

/*
 * 服务器端:
 * 	(1)接收客户端的连接
 *  (2)接收客户端的词语
 *  (3)把词语“反转”返回给客户端
 *  (2)(3)多次,直到客户端发送"bye"为止
 */
public class TestServer {
	public static void main(String[] args) throws IOException {
		//1、开启服务器
		ServerSocket server = new ServerSocket(8989);
		
		//2、接收一个客户端的连接
		Socket socket = server.accept();
		
		//3、先获取输入流和输出流
		InputStream in = socket.getInputStream();
		/*
		 * 因为是接收一个词语,反转一个,返回一个
		 * 那么如果仅仅使用字节流,不好区分词语
		 * 需要用到字符流
		 * 那么就意味着需要把字节流转为字符流
		 */
		InputStreamReader isr = new InputStreamReader(in);//这里不涉及编码问题,仅仅为了转换流的类型
		/*
		 * 字符流中几个字符是一个词语
		 * 那么我们这里选择“换行符”来作为词语的分割
		 * 意味着我们可以按行读取Scanner或BufferedReader
		 */
		BufferedReader br = new BufferedReader(isr);
		
		OutputStream out = socket.getOutputStream();
		/*
		 * 客户端收到字节,同样不方便处理几个字节是一个词语,仍然要把字节输出流转为字符流
		 * 而且字符之间也不好区分,那么也选择“换行符”进行区别词语
		 * 我们现在需要把OutputStream转为一个可以按行写的字符流或其他的处理流
		 * 
		 * 可以按行写的:BufferedWriter(newLine())
		 * 		   PrintStream(println())
		 */
		PrintStream ps = new PrintStream(out);
		
		//从客户端接收词语
		String word;
		while((word = br.readLine()) != null){
			if("bye".equals(word)){
				break;
			}
			
			//如果不是bye,要反转,并且返回
			StringBuilder sb = new StringBuilder(word);
			sb.reverse();
			
			//返回给客户端
			ps.println(sb.toString());
		}
		
		//4、断开
		socket.close();
		
		//5、关闭服务器
		server.close();
	}
}

package com.atguigu.test12;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

/*
 * 客户端:
 * (1)从键盘输入词语
 * (2)发送给服务器
 * (3)接收服务器返回的结果
 * (1)(2)(3)多次进行,直到键盘输入bye并发送给发服务器之后就结束
 */
public class TestClient {
	public static void main(String[] args) throws UnknownHostException, IOException {
		//1、连接服务器
		Socket socket = new Socket("192.168.30.142",8989);
		
		/*
		 *  * (1)从键盘输入词语
		 * (2)发送给服务器
		 * (3)接收服务器返回的结果
		 * (1)(2)(3)多次进行,直到键盘输入bye并发送给发服务器之后就结束
		 */
		Scanner input = new Scanner(System.in);
		/*
		 * 同样考虑到发送词语,以及词语之间分割问题,那我们选择PrintStream和BufferedReader
		 */
		PrintStream ps = new PrintStream(socket.getOutputStream());
		BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		while(true){
			//从键盘输入词语
			System.out.print("请输入词语:");
			String word = input.next();
			
			//发送给服务器端
			ps.println(word);
			
			if("bye".equals(word)){
				break;
			}
			
			//接收服务器返回的结果
			String result = br.readLine();
			System.out.println("服务器返回的反转后的结果:" + result);
		}
		
		input.close();
		socket.close();
	}
}

15.5.4 TCP协议编程示例四

多个客户端同时连接服务器,连接成功后:

(1)客户端从键盘输入词语,给服务器发送,直到bye为止;

(2)服务器每次手动词语,反转词语 ,然后返回给客户端,直到接收到bye为止

package com.atguigu.test13;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;

/*
 * 服务器端:
 * 	(1)接收客户端的连接
 *  (2)接收客户端的词语
 *  (3)把词语“反转”返回给客户端
 *  (2)(3)多次,直到客户端发送"bye"为止
 *  
 *  加一个条件,服务器端可以同时接收n个客户端连接
 *  服务器端得加多线程
 */
public class TestServer {
	public static void main(String[] args) throws IOException {
		//1、开启服务器
		ServerSocket server = new ServerSocket(8989);
		
		boolean flag = true;
		while(flag){
			//2、接收一个客户端的连接
			Socket socket = server.accept();//每个客户端的socket是独立的
			
			//为没一个客户端开启一个独立的线程维护它的通信
			MessageHandler mh = new MessageHandler(socket);
			mh.start();
		}
			
		//5、关闭服务器
		server.close();
	}
}
class MessageHandler extends Thread{
	private Socket socket;
	
	public MessageHandler(Socket socket) {
		super();
		this.socket = socket;
	}

	public void run(){
		try {
			//3、先获取输入流和输出流
			InputStream in = socket.getInputStream();
			/*
			 * 因为是接收一个词语,反转一个,返回一个
			 * 那么如果仅仅使用字节流,不好区分词语
			 * 需要用到字符流
			 * 那么就意味着需要把字节流转为字符流
			 */
			InputStreamReader isr = new InputStreamReader(in);//这里不涉及编码问题,仅仅为了转换流的类型
			/*
			 * 字符流中几个字符是一个词语
			 * 那么我们这里选择“换行符”来作为词语的分割
			 * 意味着我们可以按行读取Scanner或BufferedReader
			 */
			BufferedReader br = new BufferedReader(isr);
			
			OutputStream out = socket.getOutputStream();
			/*
			 * 客户端收到字节,同样不方便处理几个字节是一个词语,仍然要把字节输出流转为字符流
			 * 而且字符之间也不好区分,那么也选择“换行符”进行区别词语
			 * 我们现在需要把OutputStream转为一个可以按行写的字符流或其他的处理流
			 * 
			 * 可以按行写的:BufferedWriter(newLine())
			 * 		   PrintStream(println())
			 */
			PrintStream ps = new PrintStream(out);
			
			//从客户端接收词语
			String word;
			while((word = br.readLine()) != null){
				if("bye".equals(word)){
					break;
				}
				
				//如果不是bye,要反转,并且返回
				StringBuilder sb = new StringBuilder(word);
				sb.reverse();
				
				//返回给客户端
				ps.println(sb.toString());
			}
			
			
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			try {
				//4、断开
				socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
package com.atguigu.test13;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

/*
 * 客户端:
 * (1)从键盘输入词语
 * (2)发送给服务器
 * (3)接收服务器返回的结果
 * (1)(2)(3)多次进行,直到键盘输入bye并发送给发服务器之后就结束
 * 
 * 加一个条件,服务器端可以同时接收n个客户端连接
 * 客户端代码不用修改
 */
public class TestClient {
	public static void main(String[] args) throws UnknownHostException, IOException {
		//1、连接服务器
		Socket socket = new Socket("192.168.30.142",8989);
		
		/*
		 *  * (1)从键盘输入词语
		 * (2)发送给服务器
		 * (3)接收服务器返回的结果
		 * (1)(2)(3)多次进行,直到键盘输入bye并发送给发服务器之后就结束
		 */
		Scanner input = new Scanner(System.in);
		/*
		 * 同样考虑到发送词语,以及词语之间分割问题,那我们选择PrintStream和BufferedReader
		 */
		PrintStream ps = new PrintStream(socket.getOutputStream());
		BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		while(true){
			//从键盘输入词语
			System.out.print("请输入词语:");
			String word = input.next();
			
			//发送给服务器端
			ps.println(word);
			
			if("bye".equals(word)){
				break;
			}
			
			//接收服务器返回的结果
			String result = br.readLine();
			System.out.println("服务器返回的反转后的结果:" + result);
		}
		
		input.close();
		socket.close();
	}
}

15.5.5 TCP协议编程示例五

一个客户端连接服务器,连接成功后,给服务器上传一个文件,服务器接收到文件后存到upload的文件夹中。

package com.atguigu.test14;

import java.io.DataInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;

/*
 * 从客户端发送文件到服务器端
 * (1)接收客户端的连接
 * (2)接收文件名.后缀名
 * 思考:
 * 	 存哪里   ①在当前项目中找一个位置存储,例如:upload文件夹
 *  ②如何解决文件名重名的问题         文件名需要处理,加入时间戳或其他的唯一编码的UUID等值
 *  ③.后缀名需要保留,因为它代表文件的类型
 * (3)接收文件内容
 * (4)反馈结果
 * 
 * 思考:
 * 		这里既要接收文件名.后缀名,又要接收文件内容。
 * 		这里既有  文本信息“文件名.后缀名”,又有其他类型的数据“文件内容”,只能选择字节流。
 * 
 * 		如何区别,文件名.后缀名   与  文件内容呢
 * 		想哪种字节输入流,可以处理字符串,和字节类型的数据。
 * 
 * 		FileInputStream
 * 		BufferedInputStream
 * 		DataInputStream
 * 		ObjectInputStream
 * 
 * 		这些里面:DataInputStream:readUTF() 和  read(byte[])
 * 				ObjectInputStream也可以,但是麻烦,我这里选择DataInputStream
 * 
 */
public class TestServer {
	public static void main(String[] args) throws IOException {
		//1、开启服务器
		ServerSocket server = new ServerSocket(9999);
		
		//2、接收客户端的连接
		Socket socket = server.accept();
		
		//3、获取输入流
		InputStream in = socket.getInputStream();
		DataInputStream dis = new DataInputStream(in);
		
		//接收文件名.后缀名
		String fileName = dis.readUTF();
		
		//处理文件名
		/*
		 * 希望我要在服务器存储的文件名:   原来的文件名 + 时间戳
		 */
		long timestamp = System.currentTimeMillis();
		//.的下标
		int index = fileName.lastIndexOf(".");
		//后缀名
		String ext = fileName.substring(index);
		// 原来的文件名
		String name = fileName.substring(0, index);
		//新文件名
		String newFileName = "upload/" + name + timestamp + ext;
		
		//创建文件输出流,把接收到的文件内容,写入新文件
		FileOutputStream fos = new FileOutputStream(newFileName);
		
		//接收文件内容
		byte[] data = new byte[1024];
		int len;
		while((len = dis.read(data))!=-1){
			fos.write(data, 0, len);
		}
		
		//还可以给客户端反馈:文件接收完毕
		OutputStream out = socket.getOutputStream();
		PrintStream ps = new PrintStream(out);
		ps.println("文件接收完毕!");
		
		//断开
		fos.close();
		socket.close();
		server.close();
	}
}

package com.atguigu.test14;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

/*
 * 从客户端发送文件到服务器端
 * 
 * 
 * 客户端:
 * (1)从键盘输入文件的路径名,即选择要发送的文件
 * (2)给服务器先把“文件名.后缀名"
 * (3)发送文件内容
 * (4)接收服务器的反馈结果
 * 
 * 这里同样因为既要发送“文件名.后缀名",又要发送“文件内容”,选择字节流,选择DataOutputStream
 * 
 */
public class TestClient {
	public static void main(String[] args) throws UnknownHostException, IOException {
		//1、连接服务器
		Socket socket = new Socket("192.168.30.142",9999);
		
		//2、从键盘输入文件的路径名,即选择要发送的文件
		Scanner input = new Scanner(System.in);
		System.out.print("请选择你要发送的文件(例如:D:/尚硅谷_190513班_柴林燕_JavaSE/开学典礼所发资料.rar):");
		String fileName = input.nextLine();
		File file = new File(fileName);
		
		//3、给服务器发送“文件名.后缀名"
		OutputStream out = socket.getOutputStream();
		DataOutputStream dos = new DataOutputStream(out);
		
		//发送“文件名.后缀名"
		dos.writeUTF(file.getName());
		
		//4、发送文件内容
		//先从file文件读取内容
		FileInputStream fis = new FileInputStream(file);
		byte[] data = new byte[1024];
		int len;
		while((len = fis.read(data)) != -1){
			//一边读,一边给服务器发送
			dos.write(data,0,len);
		}
		socket.shutdownOutput();//表示发送完毕了
		
		//5、接收反馈
		InputStream in = socket.getInputStream();
		InputStreamReader isr = new InputStreamReader(in);
		BufferedReader br = new BufferedReader(isr);
		String result = br.readLine();
		System.out.println("结果:" + result);
		
		//6、关闭
		socket.close();
		fis.close();
	}
}

15.5.6 TCP协议编程示例六

多个客户端连接服务器,连接成功后,给服务器上传一个文件,服务器接收到文件后存到upload的文件夹中。

package com.atguigu.test15;

import java.io.DataInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;

public class TestServer {
	public static void main(String[] args) throws IOException {
		//1、开启服务器
		ServerSocket server = new ServerSocket(9999);
		
		while(true){
			//2、接收客户端的连接
			Socket socket = server.accept();
			
			FileUploadThread ft = new FileUploadThread(socket);
			ft.start();
		
		}
//		server.close();//不关闭服务器
	}
}
class FileUploadThread extends Thread{
	private Socket socket;
	
	public FileUploadThread(Socket socket) {
		super();
		this.socket = socket;
	}

	public void run(){
		try {
			//3、获取输入流
			InputStream in = socket.getInputStream();
			DataInputStream dis = new DataInputStream(in);
			
			//接收文件名.后缀名
			String fileName = dis.readUTF();
			
			//处理文件名
			/*
			 * 希望我要在服务器存储的文件名:   原来的文件名 + 时间戳
			 */
			long timestamp = System.currentTimeMillis();
			//.的下标
			int index = fileName.lastIndexOf(".");
			//后缀名
			String ext = fileName.substring(index);
			// 原来的文件名
			String name = fileName.substring(0, index);
			//新文件名
			String newFileName = "upload/" + name + timestamp + ext;
			
			//创建文件输出流,把接收到的文件内容,写入新文件
			FileOutputStream fos = new FileOutputStream(newFileName);
			
			//接收文件内容
			byte[] data = new byte[1024];
			int len;
			while((len = dis.read(data))!=-1){
				fos.write(data, 0, len);
			}
			
			//还可以给客户端反馈:文件接收完毕
			OutputStream out = socket.getOutputStream();
			PrintStream ps = new PrintStream(out);
			ps.println("文件接收完毕!");
			
			//断开
			fos.close();
			socket.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
package com.atguigu.test15;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class TestClient {
	public static void main(String[] args) throws UnknownHostException, IOException {
		//1、连接服务器
		Socket socket = new Socket("192.168.30.142",9999);
		
		//2、从键盘输入文件的路径名,即选择要发送的文件
		Scanner input = new Scanner(System.in);
		System.out.print("请选择你要发送的文件(例如:D:/尚硅谷_190513班_柴林燕_JavaSE/开学典礼所发资料.rar):");
		String fileName = input.nextLine();
		File file = new File(fileName);
		
		//3、给服务器发送“文件名.后缀名"
		OutputStream out = socket.getOutputStream();
		DataOutputStream dos = new DataOutputStream(out);
		
		//发送“文件名.后缀名"
		dos.writeUTF(file.getName());
		
		//4、发送文件内容
		//先从file文件读取内容
		FileInputStream fis = new FileInputStream(file);
		byte[] data = new byte[1024];
		int len;
		while((len = fis.read(data)) != -1){
			//一边读,一边给服务器发送
			dos.write(data,0,len);
		}
		socket.shutdownOutput();//表示发送完毕了
		
		//5、接收反馈
		InputStream in = socket.getInputStream();
		InputStreamReader isr = new InputStreamReader(in);
		BufferedReader br = new BufferedReader(isr);
		String result = br.readLine();
		System.out.println("结果:" + result);
		
		//6、关闭
		socket.close();
		fis.close();
		input.close();
	}
}

15.5.7 TCP协议编程示例七

群聊

package com.atguigu.test16;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Iterator;

/*
 * 
 */
public class TestServer {
	private static ArrayList<Socket> online = new ArrayList<Socket>();
	
	public static void main(String[] args) throws IOException {
		//1、开启服务器
		ServerSocket server = new ServerSocket(9999);
		
		while(true){
			//2、接收客户端的连接
			Socket socket = server.accept();
			
			//把这个客户端加入到online中
			online.add(socket);
			
			//每一个客户端独立的线程
			MessageHandler mh = new MessageHandler(socket);
			mh.start();
		}
	}

	//私有的静态的内部类
	//这里用内部类的原因,是为了用上面的online集合
	private static class MessageHandler extends Thread{
		private Socket socket;
		private String ip;
		
		public MessageHandler(Socket socket) {
			super();
			this.socket = socket;
			this.ip = socket.getInetAddress().getHostAddress();
		}

		public void run(){
			//这个客户端的一连接成功,线程一启动,就可以告诉其他人我上线了
			sendToOthers(ip+"上线了");
			
			/*
			 * (1)接收当前的客户端发送的消息
			 * (2)给其他在线的客户端转发
			 */
			//(1)接收当前的客户端发送的消息
			try {
				InputStream in = socket.getInputStream();
				InputStreamReader isr = new InputStreamReader(in);
				BufferedReader br = new BufferedReader(isr);
				
				String content;
				while((content = br.readLine()) !=null){
					if("bye".equals(content)){
						//给自己发一句bye
						OutputStream out = socket.getOutputStream();
						PrintStream ps = new PrintStream(out);
						ps.println("bye");
						
						break;
					}
					
					//收到一句,转发一句
					sendToOthers(ip+"说:" + content);
				}
				
				sendToOthers(ip+"下线了");
			} catch (IOException e) {
				sendToOthers(ip+"掉线了");
			}
		}
		
		//因为转发的代码也很长,独立为一个方法
		public void sendToOthers(String str){
			//遍历所有online的客户端
			Iterator<Socket> iterator = online.iterator();
			while(iterator.hasNext()){
				Socket on = iterator.next();
				if(!on.equals(socket)){//只给其他客户端转发
					try {
						OutputStream out = on.getOutputStream();
						PrintStream ps = new PrintStream(out);
						
						ps.println(str);
					} catch (IOException e) {
						//说明on这个客户端要么下线了,要么掉线了
						iterator.remove();
					}
				}
			}
		}
	}
	
	
}

package com.atguigu.test16;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

/*
 * 群聊
 */
public class TestClient {
	public static void main(String[] args) throws UnknownHostException, IOException {
		//1、连接服务器
		Socket socket = new Socket("192.168.30.142",9999);
		
		//2、开启两个线程,一个收消息,一个发消息
		SendThread st = new SendThread(socket);
		ReceiveThread rt = new ReceiveThread(socket);
		
		st.start();
		rt.start();
		
		//等发送线程停下来再往下走
		try {
			st.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		//让接收数据的线程停下
		rt.setFlag(false);
		
		//等接收线程停下来,再往下走,断开连接
		try {
			rt.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		socket.close();
	}
}
class SendThread extends Thread{
	private Socket socket;
	
	public SendThread(Socket socket) {
		super();
		this.socket = socket;
	}

	public void run(){
		try {
			//键盘输入
			Scanner input = new Scanner(System.in);
			OutputStream out = socket.getOutputStream();
			PrintStream ps = new PrintStream(out);
			while(true){
				//从键盘输入
				System.out.print("请输入要发送的消息:");
				String content = input.nextLine();
				System.out.println("content:" + content);
				
				//给服务器发送
				ps.println(content);
				
				//如果bye,就结束发送
				if("bye".equals(content)){
					break;
				}
			}
			input.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
class ReceiveThread extends Thread{
	private Socket socket;
	private boolean flag = true;
	
	public ReceiveThread(Socket socket) {
		super();
		this.socket = socket;
	}
	
	public void run(){
		try {
			InputStream in = socket.getInputStream();
			InputStreamReader isr = new InputStreamReader(in);
			BufferedReader br = new BufferedReader(isr);
			
			while(flag){
				String line = br.readLine();
				System.out.println(line);
				if("bye".equals(line)){
					break;
				}
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void setFlag(boolean flag) {
		this.flag = flag;
	}
	
}

15.5.8 UDP协议编程示例

package com.atguigu.test17;

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

public class TestSend {
	public static void main(String[] args) throws IOException {
		//1、发送方,建立一个Socket
		//发送方的端口号和IP地址,自动获取
		DatagramSocket ds = new DatagramSocket();
		
		//2、准备把要发送的数据打包
		String str = "马上下课了";
		byte[] bytes = str.getBytes();
		InetAddress ip = InetAddress.getByName("192.168.30.142");
		DatagramPacket dp = new DatagramPacket(bytes,0,bytes.length, ip, 9999);
		
		//3、发送,通过socket发送
		ds.send(dp);
		System.out.println("发送完毕");
		
		//4、关闭
		ds.close();
		
	}
}

package com.atguigu.test17;

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

/*
 * 接收方:
 * 	DatagramPacket(byte[] buf, int length) 
 * 	参数一:用来装数据的字节数组
 *  参数二:数组的长度
 */
public class TestReceive {
	public static void main(String[] args) throws IOException {
		//1、接收方也要socket
		//接收方的端口号,指定,IP自动获取
		DatagramSocket ds = new DatagramSocket(9999);
		
		//2、准备一个数据报,接收数据
		byte[] data = new byte[1024];
		DatagramPacket dp = new DatagramPacket(data,data.length);
		
		//3、接收数据
		ds.receive(dp);
		
		//4、把数据拆解出来
		byte[] bs = dp.getData();//接收的数据
		int len = dp.getLength();//接收的数据的实际长度
		System.out.println(new String(bs,0,len));
		
		//5、断开
		ds.close();
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值