2018-06-15 第四十天-阿里云开发者社区

开发者社区> 数据库> 正文
登录阅读全文

2018-06-15 第四十天

简介:

一、TCP



使用 Socket 对象 进行 通信 ,使用底层的TCP 协议。

 

面向连接的协议。

 

1:先建立连接。  通信的两端 都会有进行通信的Socket 对象。

2:使用Socket 对象 使用字节流进行消息的通信。

 

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.InputStreamReader;

import java.io.OutputStream;

import java.io.OutputStreamWriter;

import java.net.ServerSocket;

import java.net.Socket;

 

/**

 * 使用 Socket 连接服务器,给服务器发送一条信息。服务器收到之后,反馈一个boolean 值。

 *

 */

public class MyServer {

public static final int SERVER_PORT = 1777;

 

public static void main(String[] argsthrows Exception{

//创建建立连接服务的 服务对象。

ServerSocket ss = new ServerSocket(SERVER_PORT);

System.out.println("等待连接的请求!");

//阻塞式方法,只有连接请求发过来之后,该方法才会返回,并生成一个与连接过来的对象进行通信的Socket

Socket socket = ss.accept();

System.out.println("连接成功!---"+socket);

//获取客户端发送的数据

BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));

String str = br.readLine();

System.out.println("服务器收到的信息为:"+str);

//给客户端回复一个boolean 

DataOutputStream dos = new DataOutputStream(socket.getOutputStream());

dos.writeBoolean(true);

dos.flush();

//需要写到finally  代码

socket.close();

ss.close();

} 

}

 

class MyClient{

public static void main(String[] argsthrows Exception{

//创建连接服务器的Socket 对象

Socket socket = new Socket("127.0.0.1", MyServer.SERVER_PORT);

//给服务器发送一条信息

String str = "我可以连接你么?";

OutputStream os = socket.getOutputStream();

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));

bw.write(str);

bw.newLine();

bw.flush();

//接收服务的反馈

DataInputStream dis = new DataInputStream(socket.getInputStream());

System.out.println("服务器的反馈:"+dis.readBoolean());

dis.close();

bw.close();

socket.close();

}

}

 

二、tcp-模拟用户登录

import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.FileInputStream;

import java.net.ServerSocket;

import java.net.Socket;

import java.util.Properties;

 

/**

 * 模拟用户登录

 *

 * 客户端:发送一个用户名+密码给服务器。接收服务器的一个反馈。

 * 服务器:接收客户端的登录请求,解析客户端的用户名和密码知否有效(需要和数据库中的用户信息比对)。

 * 如果用户存在,返回 true,否则返回 false

 *

 */

public class LoginServer {

public static final int SERVER_PORT = 1777;

 

public static void main(String[] argsthrows Exception{

ServerSocket ss = new ServerSocket(SERVER_PORT);

Socket socket = ss.accept();

System.out.println(socket);

BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());

byte[] buf = new byte[100];

int count = bis.read(buf);

String str = new String(buf,0,count);

String name = str.split("&")[0].split("=")[1];

String pwd = str.split("&")[1].split("=")[1];

DataOutputStream dos = new DataOutputStream(socket.getOutputStream());

dos.writeBoolean(hasUser(name,pwd));

dos.flush();

socket.close();

ss.close();

}

/**

 * 判断 配置文件中,是否包含指定的用户

 * @param name

 * @param pwd

 * @return

 */

public static boolean hasUser(String name, String pwd)throws Exception{

Properties users = new Properties();

users.load(new FileInputStream("./res/users.txt"));

boolean bool = users.containsKey(name);

if(bool){//人存在,比对密码

if(users.getProperty(name).equals(pwd)){

return true;

}

return false;

}

return false;

}

}

 

class LoginClient{

public static void main(String[] argsthrows Exception{

Socket socket = new Socket("192.168.51.242", LoginServer.SERVER_PORT);

String str = "name=xiaogang&pwd=123456";

byte[] buf = str.getBytes();

BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

bos.write(buf);

bos.flush();

DataInputStream dis = new DataInputStream(socket.getInputStream());

System.out.println("服务器的反馈:"+dis.readBoolean());

//只关闭socket 即可。

socket.close();

}

}

 

三、tcp-转换大写

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.InputStreamReader;

import java.io.OutputStreamWriter;

import java.net.ServerSocket;

import java.net.Socket;

 

/**

 * 需求:客户端给服务器发送一个字符串,可以多次发送,服务器接收到之后,将字符串的大写形式返回。

 * 客户端发送一个bye,结束转换

 *

 */

public class UpperCaseServer {

//收到字符串,转换为大写返回

public static final int SERVER_PORT = 1777;

public static final String BYE_STR = "bye";

 

public static void main(String[] argsthrows Exception{

ServerSocket ss = new ServerSocket(SERVER_PORT);

//监听连接请求

Socket socket = ss.accept();

System.out.println(socket);

//得到读取输入流的字符输入流,,得到往输出流写数据的字符输出流

// br 用于读取小写信息

BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));

//bw 用户回复大写

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

while(true){

//读取客户端发送的内容,转换大写,回复,切记要刷新

String string = br.readLine();

if(BYE_STR.equals(string)){

break;

}

bw.write(string.toUpperCase());

bw.newLine();

bw.flush();

}

socket.close();

ss.close();

}

}

 

class UpperCaseClient{

public static void main(String[] argsthrows Exception{

Socket socket = new Socket("192.168.51.242", UpperCaseServer.SERVER_PORT);

//bw 用于发送给服务器信息的 字符输出流

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

//br 用于读取服务器反馈的

BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));

//用于本地输入的

BufferedReader input = new BufferedReader(new InputStreamReader(System.in));

while(true){

System.out.println("请您输入要转换的内容:");

//接收键盘的输入

String string = input.readLine();

//string 发送给服务器

bw.write(string);

bw.newLine();

bw.flush();

//如果输入了bye ,结束 循环

if(UpperCaseServer.BYE_STR.equals(string))

break;

//读取服务器的反馈

String response = br.readLine();

System.out.println(response);

}

socket.close();

}

}

 

四、tcp-上传文件

import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.net.ServerSocket;

import java.net.Socket;

 

/**

 * 服务器上传文件:

 *

 * 客户端:

 * 1:先把文件的名字传给服务器

 * 2:读取本地文件的数据,发送给服务器。

 *

 * 服务器:

 * 1:接收文件的名字

 * 2:接收文件数据,写入到本地。

 *

 */

public class UploadFileServer {

public static final int PORT = 1777;

 

public static void main(String[] argsthrows Exception{

ServerSocket ss = new ServerSocket(PORT);

 

Socket socket = ss.accept();

System.out.println(socket);

 

DataInputStream dis = new DataInputStream(socket.getInputStream());

//获得文件的名字

String fileName = dis.readUTF();

//写到本地字节输出流

BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("c:/server/"+fileName));

//读取客户端发送的数据

BufferedInputStream bis =new BufferedInputStream(socket.getInputStream());

byte[] buf = new byte[100];

int count = bis.read(buf);

while(count != -1){

bos.write(buf, 0, count);

count = bis.read(buf);

}

bos.flush();

bos.close();

 

//给客户端的反馈

DataOutputStream dos = new DataOutputStream(socket.getOutputStream());

dos.writeUTF(fileName + "\t上传成功!");

dos.flush();

 

socket.close();

ss.close();

}

}

 

class UploadFileClient{

 

public static void main(String[] argsthrows Exception{

Socket socket = new Socket("192.168.51.242", UploadFileServer.PORT);

 

File file = new File("c:/dear.jpg");

//将文件的名字发过去

String name = file.getName();

DataOutputStream dos = new DataOutputStream(socket.getOutputStream());

dos.writeUTF(name);

dos.flush();

//可以得到文件的字节大小,给服务器发过去。

//发送字节数据 

//读取本地字节数据

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));

//将读取到的字节数据发送出去

BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

 

byte[] buf = new byte[100];

//读取本地字节数据

int count = bis.read(buf);

while(count != -1){

bos.write(buf, 0, count);

//读取本地字节数据

count = bis.read(buf);

}

 

bos.flush();

bis.close();

 

//给输出流添加一个流的末尾的标识,不会影响其他的流

socket.shutdownOutput();

 

//接收服务器的反馈 ,文件上传成功

DataInputStream dis = new DataInputStream(socket.getInputStream());

System.out.println("服务器反馈:"+dis.readUTF());

 

socket.close();

}

}

 

五、tcp-并发上传

import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.FileOutputStream;

import java.net.ServerSocket;

import java.net.Socket;

import java.util.ArrayList;

 

/**

 * 服务器上传文件:

 *

 * 服务器:

 * 1:可以同时 响应多个客户端上传文件的请求 

 * 2:需要满足一个客户端 多次上传同一个文件的需求。

 *  客户端的IP地址 + 当前时间的时间戳(System.currentTimeMillis() + 文件名.txt

 */

public class UploadFileServer {

public static final int PORT = 1777;

 

public static void main(String[] argsthrows Exception{

ServerSocket ss = new ServerSocket(PORT);

ArrayList<Socket> sockets = new ArrayList<>();

 

try {

while(true){

Socket socket = ss.accept();

//得到一个socket 连接之后,立马启动一个线程,该线程负责 当前得到的socket 对象和 与之对应的客户端的通信。

sockets.add(socket);

System.out.println(socket);

//来了一个请求,就需要启动一个线程,该线程负责和该请求进行通信。

new SocketThread(socket).start();

}

finally {

ss.close();

}

}

/**

 * 用来和客户端的一个请求的socket 进行通信的。

 *

 */

static class SocketThread extends Thread{

private Socket socket;

public SocketThread(Socket socket) {

this.socket = socket;

}

@Override

public void run() {

try {

DataInputStream dis = new DataInputStream(socket.getInputStream());

//获得文件的名字

String fileName = dis.readUTF();

//写到本地字节输出流

//TODO

String ip = socket.getInetAddress().getHostAddress();

String timeStr = Long.toString(System.currentTimeMillis());

BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("c:/server/"+ip+"_"+timeStr + "_"fileName));

//读取客户端发送的数据

BufferedInputStream bis =new BufferedInputStream(socket.getInputStream());

byte[] buf = new byte[10000];

int count = bis.read(buf);

while(count != -1){

bos.write(buf, 0, count);

count = bis.read(buf);

//Thread.sleep(10);

}

bos.flush();

bos.close();

 

//给客户端的反馈

DataOutputStream dos = new DataOutputStream(socket.getOutputStream());

dos.writeUTF(fileName + "\t上传成功!");

dos.flush();

 

socket.close();

catch (Exception e) {

e.printStackTrace();

}

}

}

}

 

六、断点续传

1:从服务器下载文件。

第一步:给服务器发送一个 下载文件的名字(String);

第二步服务从本地读取指定的文件,再通过输出流发送给客户端。

断了。

 

2:需要发送2调数据:

1:想要下载的文件的名字。

2:已经下载的文件的大小。

服务器收到已经下载的字节数据的大小,从指定的位置开始读取文件下发给客户端。

---- skip(1024*1024)。

 

import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.net.ServerSocket;

import java.net.Socket;

 

/**

 * 从服务器下载文件。断点续传

 *

 */

public class DownLoadFileServer {

public static final int SERVER_PORT = 1777;

 

public static void main(String[] argsthrows Exception{

ServerSocket ss = new ServerSocket(SERVER_PORT);

Socket socket = ss.accept();

//读取文件的名字

DataInputStream dis = new DataInputStream(socket.getInputStream());

String fileName = dis.readUTF();

//读取文件的大小(已经下载的文件大小)

long size = dis.readLong();

//发送文件是否存在

File file = new File("c://server/"+fileName);

DataOutputStream dos = new DataOutputStream(socket.getOutputStream());

boolean exist = file.exists();

dos.writeBoolean(exist);

if(!exist){//文件不存在,结束

socket.close();

ss.close();

return;

}

//读取本地数据,发送给客户端

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));

BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

byte[] buf = new byte[1000];

//从文件指定的位置读取

bis.skip(size);

int count = bis.read(buf);

while(count!= -1){

bos.write(buf,0,count);

bos.flush();

count = bis.read(buf);

}

bis.close();

socket.close();

ss.close();

}

}

 

/**

 * 服务器下载文件,客户端

 *

 */

class DownLoadFileClient{

public static void main(String[] argsthrows Exception{

Socket socket = new Socket("192.168.51.242" , DownLoadFileServer.SERVER_PORT);

//发送请求文件名字

File file = new File("c://dear.jpg");

String fileName = file.getName();

DataOutputStream dos = new DataOutputStream(socket.getOutputStream());

dos.writeUTF(fileName);

dos.flush();

//如果文件存在,发送文件大小给服务器,不存在发送给服务器

long size = 0;

if(file.exists()){

size = file.length();

}

dos.writeLong(size);

dos.flush();

//接收服务器的反馈,如果服务器文件不存在,则直接终止程序

DataInputStream dis = new DataInputStream(socket.getInputStream());

boolean fileExist = dis.readBoolean();

if(!fileExist){

System.out.println("请求文件不存在,下载 失败!");

socket.close();

return;

}

//接收服务器发送的数据写到本地。切记要写入指定的文件,尾部追加

BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filetrue));

BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());

byte[] buf = new byte[1000];

int count = bis.read(buf);

while(count != -1){

bos.write(buf, 0, count);

bos.flush();

count = bis.read(buf);

Thread.sleep(10);

}

bos.close();

socket.close();

}

}

 

七、网络编程中的注意事项

1:如果涉及到缓冲流,Buffered 相关的, 要及时对流进行刷新 调用flush 方法。

2:关闭流的时候,只需要关闭socket ,关闭socket 就会把socket 的inputStream 和OutputStream 同时关闭。

3:如果需要关闭socket 的inputStream 和OutputStream 先关输入输出流,再关socket。

4:如果涉及到readLine 方法。需要保证对方会发送一行数据已经行的结束标识。  newLine() 或者使用PrintWriter 要打开自动刷新功能。  的println()。

5:通过关闭socket的输入输出流 通过close 关闭 ,都会导致socket不可用。

6:通过shutDownInputStream 和  shutDownOutputStream 只会单方面的关闭某一个流,不会导致另外的一个流不可用。

 

八、泛型

1:概念:泛型:generic type---参数化类型。

 

2:泛型的有效期:编译期。

泛型是从java 源文件 编程成 class 的过程中,对泛型约束的类型进行检查。

class 文件中。所有的泛型相关的信息都将被擦除掉。

运行期将不再进行泛型类型的检查。

 

3:泛型类

class MyStack<T>{

t;

void test(T t){

}

}

 

4:泛型接口---泛型接口实现子类。

interface MyInterface<T>{

void test(T t);

}

//子类实现父接口,如果父接口是一个泛型接口,那么子类的也许要指定泛型,和父接口类型一致。

class MyInterfaceImpl<Integerimplements MyInterface<Integer>{

@Override

public void test(Integer t) {

}

}

 

5:泛型通配符(方法参数泛型不固定)

//? 泛型通配符,可以认为是所有泛型类型的父类型

//? 某种特定的类型。可以是任意类型。

static void test(ArrayList<?> list){

}

这个时候,调用该方法,list 中的元素的类型可以是任意类类型。

 

6:复杂的泛型方法:

声明

使用

泛型类中使用泛型方法

 

7:静态方法与泛型

泛型类中的静态的方法,不能直接使用类的泛型类型。因为类的泛型的类型是依赖于对象的。而静态方法是依赖于类加载。

如果想在静态方法中使用泛型类的类型,那么必须将该方法声明成泛型方法。

(静态泛型方法的泛型的类型可以和所在的类的泛型的类型相同,也可以不同)

8:泛型的上下边界

方法参数的边界控制 

//希望元素的类型是 Number  Number 的子类类型

static void test1(List<? extends Number> list){

}

//希望元素的类型是 Number  Number 的父类的类型

static void test2(List<? super Number> list){

}

 

//泛型类的边界的控制 T

class MyStack<T extends Number>

 

//泛型方法边界 <T extends Number>

 

//泛型方法的边界的控制

//只能是Number 的子类和 Number 的类型

static <T extends Number> void test1(T t){

}

 

例:

import java.util.ArrayList;

import java.util.List;

 

public class Test1 {

 

public static void main(String[] args) {

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

list.add("123");

//list.add(1);

 

MyStack<Stringstack = new MyStack<>();

test(new ArrayList<String>());

//test1("123");

test1(new ArrayList<Object>());

}

//? 泛型通配符,可以认为是所有泛型类型的父类型

static void test(ArrayList<?> list){

}

//希望元素的类型是 Number  Number 的子类类型

static void test1(List<? extends Number> list){

}

//希望元素的类型是 Number  Number 的父类的类型

static void test2(List<? super Number> list){

}

//泛型方法

//static <T>  void test1(T t){

////t 只能当Object 用。

//}

}

 

class Student implements Comparable<Student>{

private int age;

 

@Override

public int compareTo(Student o) {

//Student student = (Student)o;

return age-o.age;

}

}

 

//容器中元素的类型只能是 Number  Number 的子类类型。

class MyStack<T extends Number>{

t;

 

<E> void test(E t){

}

//泛型方法的边界的控制

//只能是Number 的子类和 Number 的类型

static <T extends Number> void test1(T t){

}

}

 

interface MyInterface<T>{

void test(T t);

}

//子类实现父接口,如果父接口是一个泛型接口,那么子类的也许要指定泛型,和父接口类型一致。

class MyInterfaceImpl<Integerimplements MyInterface<Integer>{

@Override

public void test(Integer t) {

 

}

}

 

 

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
数据库
使用钉钉扫一扫加入圈子
+ 订阅

分享数据库前沿,解构实战干货,推动数据库技术变革

其他文章