Java基础学习总结:网络编程之(二)TCP编程

TCP编程

一、TCP概念

TCP,Transmission Control Protocol,传输控制协议,基于字节流的传输层通信协议。

特点:

  1. 安全、可靠
  2. 面向连接
  3. 传输数据大小限制,一旦连接建立,双方可以按统一的格式传输大的数据
  4. 效率低

TCP的三次握手

  1. 客户端向服务端发送一个请求
  2. 服务端收到请求后,回客户端一个响应
  3. 客户端向收到服务端的响应后,回服务端一个确认信息

二、基于TCPSocket(套接字)通信模型

TCP 网络程序是指利用 Socket 编写的通信程序。利用 TCP 协议进行通信的两个应用程序是有主次之分的,一个是服务器程序,一个是客户端程序,两者的功能和编写方法不太一样。其中 ServerSocket 类表示 Socket 服务器端,Socket 类表示 Socket 客户端,两者之间的交互过程如下:

  1. 服务器端创建一个 ServerSocket(服务器端套接字),调用 accept() 方法等待客户端来连接。
  2. 客户端程序创建一个 Socket,请求与服务器建立连接。
  3. 服务器接收客户的连接请求,同时创建一个新的 Socket 与客户建立连接,服务器继续等待新的请求。

Socket通信模型:

三、ServerSocket和Socket

1、ServerSocket 类

ServerSocket 类是与 Socket 类相对应的用于表示通信双方中的服务器端,用于在服务器上开一个端口,被动地等待数据(使用 accept() 方法)并建立连接进行数据交互。

服务器套接字一次可以与一个套接字连接,如果多台客户端同时提出连接请求,服务器套接字会将请求连接的客户端存入队列中,然后从中取出一个套接字与服务器新建的套接字连接起来。若请求连接大于最大容纳数,则多出的连接请求被拒绝;默认的队列大小是 50。

(1)ServerSocket 的构造方法和常用方法

构造方法:

构造方法描述
ServerSocket()无参构造方法。
ServerSocket(int port)创建绑定到特定端口的服务器套接字。
ServerSocket(int port,int backlog)使用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口。
ServerSocket(int port,int backlog,InetAddress bindAddr)

使用指定的端口、监听 backlog 和要绑定到本地的 IP 地址创建服务器。

在上述方法的参数中 port 指的是本地 TCP 端口,backlog 指的是监听 backlog,bindAddr 指的是要将服务器绑定到的 InetAddress。

常用方法:

方法描述
Socket accept()监听并接收到此套接字的连接。
void bind(SocketAddress endpoint)将 ServerSocket 绑定到指定地址(IP 地址和端口号)。
void close()关闭此套接字。
InetAddress getInetAddress()返回此服务器套接字的本地地址。
int getLocalPort()返回此套接字监听的端口。
SocketAddress getLocalSoclcetAddress()返回此套接字绑定的端口的地址,如果尚未绑定则返回 null。
int getReceiveBufferSize()获取此 ServerSocket 的 SO_RCVBUF 选项的值,该值是从 ServerSocket 接收的套接字的建议缓冲区大小。

调用 accept() 方法会返回一个和客户端 Socket 对象相连接的 Socket 对象。服务器端的 Socket 对象使用 getOutputStream() 方法获得的输出流,将指定客户端 Socket 对象使用 getInputStream() 方法获得那个输入流。同样,服务器端的 Socket 对象使用的 getInputStream() 方法获得的输入流,将指向客户端 Socket 对象使用的 getOutputStream() 方法获得的那个输出流。也就是说,当服务器向输出流写入信息时,客户端通过相应的输入流就能读取,反之同样如此。

2、Socket

Socket 类表示通信双方中的客户端,用于呼叫远端机器上的一个端口,主动向服务器端发送数据(当连接建立后也能接收数据)。

(1)Socket 类的构造方法和常用方法

构造方法

方法描述
Socket()无参构造方法。
Socket(InetAddress address,int port)创建一个流套接字并将其连接到指定 IP 地址的指定端口。
Socket(InetAddress address,int port,InetAddress localAddr,int localPort)创建一个套接字并将其连接到指定远程地址上的指定远程端口。
Socket(String host,int port)创建一个流套接字并将其连接到指定主机上的指定端口。
Socket(String host,int port,InetAddress localAddr,int localPort)创建一个套接字并将其连接到指定远程地址上的指定远程端口。Socket 会通过调用 bind() 函数来绑定提供的本地地址及端口。

在上述方法的参数中,address 指的是远程地址,port 指的是远程端口,localAddr 指的是要将套接字绑定到的本地地址,localPort 指的是要将套接字绑定到的本地端口。

常用方法:

方法描述
void bind(SocketAddress bindpoint)将套接字绑定到本地地址。
void close()关闭此套接字。
void connect(SocketAddress endpoint)将此套接字连接到服务器。
InetAddress getInetAddress()返回套接字的连接地址。
InetAddress getLocalAddress()获取套接字绑定的本地地址。
InputStream getInputStream()返回此套接字的输入流。
OutputStream getOutputStream()返回此套接字的输出流。
SocketAddress getLocalSocketAddress()返回此套接字绑定的端点地址,如果尚未绑定则返回 null。
SocketAddress getRemoteSocketAddress()返回此套接字的连接的端点地址,如果尚未连接则返回 null。
int getLoacalPort()返回此套接字绑定的本地端口。
intgetPort()返回此套接字连接的远程端口。

四、基于TCP的Socket编程

示例一:

客户端发送数据,服务器接收消息,然后两个Socket相继关闭。

服务器:

package basis.stuJavaNet.StuTCP_1;

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

public class TCPServer {
    public static void main(String[] args){
        ServerSocket server = null;
        BufferedReader br = null;
        try {
            server = new ServerSocket(10086);
            System.out.println("服务器已启动。。。");
            //监听端口
            Socket socket = server.accept();
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String data = br.readLine();
            System.out.println("客户端说:"+data);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                br.close();
                server.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        System.out.println("服务器已关闭。");
    }
}

客户端:

package basis.stuJavaNet.StuTCP_1;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class TCPClient {
    public static void main(String[] args){
        Socket client = null;
        BufferedWriter bw = null;
        try {
            client = new Socket("localhost",10086);
            System.out.println("客户端已启动。。。");
            bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
            String data = "Hello,张三";
            bw.write(data);
            bw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                bw.close();
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println("客户端关闭。");
    }
}

示例二:

客户端发送数据,服务器接收并回复,客户端接收服务器的回复,然后客户端服务器相继关闭。

服务器:

package basis.stuJavaNet.StuTCP_2;

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

public class TCPServer {
    public static void main(String[] args){
        ServerSocket server = null;
        try {
            server = new ServerSocket(10086);
            System.out.println("服务器已启动。。。");
            //监听端口
            Socket socket = server.accept();
            InputStream inputStream = socket.getInputStream();

            byte[] arr = new byte[1024];
            int len = inputStream.read(arr);
            String data = new String(arr,0,len);

            System.out.println("...");

            String address = socket.getInetAddress().getHostAddress();
            int port = socket.getPort();

            System.out.println("客户端"+address+":"+port+"说:"+data);
            //服务器回复
            OutputStream outputStream = socket.getOutputStream();
            outputStream.write("李四,你也好,好久不见。".getBytes());
            outputStream.flush();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                server.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        System.out.println("服务器已关闭。");
    }
}

客户端:

package basis.stuJavaNet.StuTCP_2;

import java.io.*;
import java.net.Socket;

public class TCPClient {
    public static void main(String[] args){
        Socket client = null;
        try {
            client = new Socket("localhost",10086);
            System.out.println("客户端已启动。。。");

            OutputStream outputStream = client.getOutputStream();
            String data = "张三,你好,好久不见。";
            outputStream.write(data.getBytes());
            outputStream.flush();

            System.out.println("...");
            InputStream inputStream = client.getInputStream();
            byte[] arr = new byte[1024];
            int len = inputStream.read(arr);

            String reply = new String(arr,0,len);

            System.out.println("...");
            System.out.println("服务器回复:"+reply);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println("客户端关闭。");
    }
}

示例三:

客户端上传文件,服务器接收文件,以图片为例。

服务器:

package basis.stuJavaNet.StuTCP_3;

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

public class TCPServer {
    public static void main(String[] args){
        ServerSocket server = null;
        try {
            server = new ServerSocket(10086);
            System.out.println("服务器已启动。。。");
            Socket socket = server.accept();
            System.out.println("客户端已连接。。。");

            BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("e:test//haha.jpg")));

            byte[] arr = new byte[1024];
            int len = 0;
            while ((len=bis.read(arr))!=-1){
                bos.write(arr,0,len);
                bos.flush();
            }
            System.out.println("上传文件成功。。。");
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                server.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println("服务器已关闭。");
    }
}

客户端:

package basis.stuJavaNet.StuTCP_3;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.net.Socket;

public class TCPClient {
    public static void main(String[] args){
        Socket client = null;
        try {
            client = new Socket("localhost",10086);

            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("e:111.jpg")));
            BufferedOutputStream bos = new BufferedOutputStream(client.getOutputStream());

            byte[] arr = new byte[1024];
            int len = 0;
            while ((len = bis.read(arr))!=-1){
                bos.write(arr,0,len);
                bos.flush();
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                client.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        System.out.println("客户端已关闭。");
    }
}

示例四:

多个客户端和一个服务器端通信(多线程)

服务器:

package basis.stuJavaNet.StuTCP_4;

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

public class TcpServer {
    public static void main(String[] args) {
        ServerSocket server = null;
        try {
            server = new ServerSocket(10086);
            System.out.println("服务器已启动。。。");
            while (true){
                Socket client = server.accept();
                ServerThread thread = new ServerThread(client);
                thread.start();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

class ServerThread extends Thread{
    private Socket client;

    public ServerThread(){}

    public ServerThread(Socket client){
        this.client = client;
    }

    @Override
    public void run() {

        try {
            OutputStream outputStream = client.getOutputStream();
            InputStream inputStream = client.getInputStream();
            Scanner scanner = new Scanner(System.in);

            while (true){
                byte[] arr = new byte[1024];
                int len = inputStream.read(arr);
                String message = new String(arr,0,len);

                //约定
                if(message.equals("886")||message.equals("baibai")){
                    String clientName = client.getInetAddress().getHostAddress();

                    System.out.println(clientName+"已退出连接");
                    break;
                }

                System.out.println("来自客户端的消息:"+message);

                //回复消息
                System.out.println("服务器对客户端说:");
                String message1 = scanner.next();
                outputStream.write(message1.getBytes());
                outputStream.flush();
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

客户端:

package basis.stuJavaNet.StuTCP_4;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class TCPClient {
    public static void main(String[] args) {
        Socket client = null;

        try {
            client = new Socket("localhost",10086);
            OutputStream outputStream = client.getOutputStream();
            InputStream inputStream = client.getInputStream();

            Scanner input = new Scanner(System.in);
            while (true){
                System.out.println("客户端对服务器说:");
                String message = input.nextLine();



                //发送
                outputStream.write(message.getBytes());
                outputStream.flush();

                //约定
                if (message.equals("886")||message.equals("baibai")){
                    break;
                }

                //接受消息
                byte[] arr = new byte[1024];
                int len = inputStream.read(arr);
                String reply = new String(arr,0,len);

                System.out.println("服务器回复:"+reply);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

示例五:

TCP实现注册登录。

服务器:

package basis.stuJavaNet.StuTCP_5;

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

public class TCPServer {

    private  ServerSocket registerSocket;//用来注册
    private  ServerSocket loginSocket;//用来登录

    private Properties userList = new Properties();//存储用户

    {
        try {
            userList.load(new BufferedInputStream(new FileInputStream(new File("userList.properties"))));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public  void start(){

        //开启注册服务
        new Thread(){
            @Override
            public void run() {
                startRegisterService();
            }
        }.start();

        //开启登录服务
        new Thread(){
            @Override
            public void run() {
                startLoginService();
            }
        }.start();
    }
    private void startRegisterService(){
        try {
            this.registerSocket = new ServerSocket(6666);
            while (true){
                Socket socket = registerSocket.accept();
                System.out.println(socket+"连接到服务器。");

                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String message = reader.readLine();
                System.out.println(message);

                String[] arr = message.split(",");
                if (this.userList.containsKey(arr[0]) && this.userList.containsKey(arr[1])){
                    System.out.println("用户名已存在。");
                }else {
                    this.userList.setProperty(arr[0],arr[1]);
                    this.userList.store(new BufferedOutputStream(new FileOutputStream(new File("userList.properties"))),"add an user");
                    System.out.println("注册成功。");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                this.registerSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void startLoginService(){
        try {
            this.loginSocket = new ServerSocket(7777);
            Socket socket = this.loginSocket.accept();

            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String message = reader.readLine();
            String[] arr = message.split(",");
            if(this.userList.containsKey(arr[0])){
                if (arr[1].equals(this.userList.getProperty(arr[0]))){
                    System.out.println("登录成功。");
                }else {
                    System.out.println("用户名或密码错误。");
                }
            }else {
                System.out.println("还未注册,请先注册");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

客户端:

package basis.stuJavaNet.StuTCP_5;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class TCPClient {

    public void doRegister(String userName,String password){
        realAction(userName,password,"localhost",6666);
    }

    public void doLogin(String userName,String password){
        realAction(userName,password,"localhost",7777);
    }

    private void realAction(String userName,String password,String ip,int port){
        Socket client = null;

        try {
            client = new Socket(ip,port);
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
            writer.write(userName+","+password);
            writer.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

测试:

第一步:开启服务器

package basis.stuJavaNet.StuTCP_5;

public class StartServer {
    public static void main(String[] args) {
        TCPServer server = new TCPServer();
        server.start();
    }
}

第二步:开启一个注册客户端

package basis.stuJavaNet.StuTCP_5;

public class TestRegister {
    public static void main(String[] args) {
        TCPClient client = new TCPClient();
        client.doRegister("lisi","123");
    }
}

第三步:开启一个登录客户端

package basis.stuJavaNet.StuTCP_5;

public class TestLogin {
    public static void main(String[] args) {
        TCPClient client = new TCPClient();
        client.doLogin("lisi","123");
    }
}

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值