高级网络编程——Sockets、java I/O

Socket概念:socket是一套用于不同主机间通信的API,它工作在我们TCP/IP协议栈上。

a Socket is an abstraction of a network interface(套接字是网络接口的一个抽象概念)

若要通过socket与不同主机之间建立通信,需要指定主机的一个ip地址和一个端口号,(ip地址用于唯一标识你的网络设备,端口用于区分主机上不同的应用)

通过socket,可以建立一条不同主机之间的虚拟数据通道 ,并且是点对点(应用对应用)的,可以想象为一条数据线连接到不同应用的插槽上。

TCP and UDP

TCP:Transmission Control Protocol 传输控制协议(基于数据流Data Stream的协议)

两个特点:

1.可靠,它的底层会自动检测并回传丢失的数据包——意思,你发送的数据对方一定会接受到。

2.稳定,发送和接受到的数据顺序是一致的。比如,你发送的一串字符“HELLO”,对方接受到的字符是完全一样的。

注意:TCP要求收发数据的双方扮演不同的角色:服务器和客户端,服务器会被动等待客户端的连接,他不会主动发起请求。

UDP:User Datagram Protocol 用户报文协议

以报文(Datagrm)为单位来收发数据,并且UDP不会自动回传丢失的数据包,因此不保证数据一定能被对方接受到,也正因为少了这些检查,UDP通常拥有更低的延迟并且占用更少的系统资源,它更适合像视频语言通话这种实时性较高的应用。

Stream:java中分为字节流(byte streams)和字符流(character streams)

byte streams:机器格式数据,数据由0和1组成,人看不懂。好处:非常高效

character streams:人可以读懂,需要机器翻译但比较慢。

Socket在编程中的应用:

编程时需要加的包:import java.net.*;

如何通过java查询已知域名的地址,如:“www.qmul.ac.uk"

socket会为程序员提供一个stream,因此你不需要担心网络如何send bytes,你只需要与数据流进行交互

(C/S架构)Servers and Clients:

server: One machine has to stay and listen 
client: The other machine makes requests
服务器只负责听,如果没收 到任何请求,则什么也不做
在java中获取本机地址的三种方式:

Ports 端口:在机器上运行的特定服务的唯一标识符。
The port is not a physical location in a machine, but a software abstraction
一个IP地址不足以识别一个唯一的服务器,许多服务可以存在于一台机器上:例如,电子邮件服务器、web服务器、ftp服务器。
在设置客户端或服务器时:1.必须选择一个端口。2.客户端和服务器都同意连接。
有几个标准端口总是用于相同的应用程序:
80端口用于web服务器——HTTP
443端口用于加密的web服务器——HTTPS
22端口用于secure shell——SSH
20和21端口用于文件传输协议——FTP
25端口用于简单的邮件传输协议——SMTP

一个简单的服务器和客户端:Server and Client

服务端的socket程序分成两个模块,即等待连接模块和负责与客户端通信的模块 。当服务器程序启动并读取配置文件完成初始化操作后,就会运行等待连接模块。这个模块会创建套接字,然后进入等待连接的暂停状态。接下来,当 客户端连发起连接时,这个模块会恢复运行并接受连接,然后启动客户端通信模块,并移交完成连接的套接字。接下来,客户端通信模块就会使用已连接的套接字与客户端进行通信,通信结束后,这个模块就退出了。

Server服务端代码:

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

public class Server {
    public static final int PORT = 2333;

    public static void main(String[] args) throws Exception {
        ServerSocket s = new ServerSocket(PORT);
        System.out.println("start");
        try {
            Socket socket = s.accept();// 等待有人接入 阻塞blocked
            try {
                System.out.println("conect:" + socket);
                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),
                        true);
                while (true) {
                    String str = in.readLine();
                    if (str == "null" || str.equals("END")) {
                        break;
                    } else {
                        System.out.println("Echoing:" + str);
                        out.println(str);
                    }
                }
            } finally {
                System.out.println("closing....");
                socket.close();
            }
        } finally {
            s.close();
        }
    }
}

Client客户端代码:

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

public class Client {
    public static final int PORT = 2333;

    public static void main(String[] args) throws Exception {
        InetAddress addr = InetAddress.getByName(null);
        System.out.println("addr=" + addr);
        Socket socket = new Socket(addr, 2333);
        try {
            System.out.println("socket:" + socket);
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),
                    true);
            for (int i = 1; i <= 10; i++) {
                out.println("Message" + i);
                String str = in.readLine();
                System.out.println(str);
            }
            out.println("END");
        } finally {
            socket.close();
        }
    }
}

其中,ServerSocket 和 socket的区别:SeverSocket用accept()方法等待客户端接入,然后产生一个socket,然后通过这个socket去与其他客户进行连接、通信。

注意:以上两段代码全背!!!!!

局限性:以上情况只能一次处理一个客户端,但往往我们需要同时处理多个客户端。例如上述情况,我的服务端连接到我的服务器之后,我的服务端一结束,我的服务器也没了。比如我登陆QQ连接了腾讯的服务器,当我把我的QQ关闭后,腾讯的服务器也没了,这个问题就很尴尬。

于是,写一个MultiSever的类:可以给多个用户服务(弱化版,一次给一个人服务,服务完之后又进入等待状态,而不是结束)

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

public class MultiServer {
    public static final int PORT = 2333;

    public static void main(String[] args) throws Exception {
        ServerSocket s = new ServerSocket(PORT);
        System.out.println("start");
        while (true) {
            try {
                Socket socket = s.accept();// 等待有人接入 阻塞blocked
                try {
                    System.out.println("conect:" + socket);
                    BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    PrintWriter out = new PrintWriter(
                            new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),
                            true);
                    while (true) {
                        String str = in.readLine();
                        if (str == "null" || str.equals("END")) {
                            break;
                        } else {
                            System.out.println("Echoing:" + str);
                            out.println(str);
                        }
                    }
                } finally {
                    System.out.println("closing....");
                    socket.close();
                }
            } finally {
            }
        }
    }
}

相比较于Server,多加了一个while(true) 即可无限循环服务

强化版,多线程:

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

class ClientThread extends Thread {
    private Socket socket;
    private BufferedReader in;
    private PrintWriter out;
    private static int counter = 0;
    private int id = counter++;
    private static int threadcount = 0;

    public static int threadCount() {
        return threadcount;
    }

    public ClientThread(InetAddress addr) {
        System.out.println("Making client" + id);
        threadcount++;
        try {
            socket = new Socket(addr, MultiServer.PORT);
        } catch (IOException e) {
            System.err.println("Socket failed");
        }
        try {
            in = new BufferedReader(
                    new InputStreamReader(socket.getInputStream()));
            out = new PrintWriter(new BufferedWriter(
                    new OutputStreamWriter(
                            socket.getOutputStream())),
                    true);
            start();
        } catch (IOException e) {
            try {
                socket.close();
            } catch (IOException e2) {
                System.err.println("Socket not closed");
            }
        }
    }

    public void run() {
        try {
            for (int i = 0; i < 5; i++) {
                out.println("Client :" + id + ": " + i);
                String str = in.readLine();
                System.out.println(str);
            }
            out.println("END");
        } catch (IOException e) {
            System.err.println("IO Exception");
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                System.err.println("Socket not closed");
            }
            threadcount--;
        }
    }
}
import java.net.*;
import java.io.*;

//多线程,强化版    
public class MultiClient {
    static final int MAX_THREADS = 40;

    public static void main(String[] args) throws IOException, InterruptedException {
        InetAddress addr = InetAddress.getByName(null);
        while (true) {
            if (ClientThread.threadCount() < MAX_THREADS)
                new ClientThread(addr);
            Thread.currentThread().sleep(100);
        }
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值