Socket network programming cottage WEB server +

Socket Network Programming

I. Overview of Network Programming

javaEE development, do some middleware, the underlying implementation principle, how communication is through the underlying network programming.

What is network programming?
  Essence of network programming is the exchange of data between two devices, of course, in a computer network, mainly refers to computer equipment. Data transfer itself is not much more difficult, not that one device to send data to a device outside the two, and another device receiving a data feedback.
  Network programming is now basically based on the request / response mode, which is a data device sends a request to another, and then another device receiving the feedback.
  Network programming, the program initiates the connection, i.e. the first request transmission program, called client (Client), waiting for the connection of other programs is called a server (Server). The client program can be started in time of need, and the server to be able to connect the appropriate time, you need to have to start. For example, to call for example, first dial the person similar to the client, person answering the phone must remain unblocked phone similar to the server.
  Once the connection is established, the client and the server can transfer the data, and the identity of the two are equivalent.

  In some programs, the program also features both client server function, the most common software is BT, emule this type of software.


IP addresses and domain names
  in real life, we need to know if you want to call the telephone number corresponding to the human, if you want to send a letter you need to know the recipient's address. In the network, too, needs to know the location of a device, it is necessary to use the IP address of the device, is connected to the specific process implemented by hardware, the programmer does not need much care.
  It is a predetermined IP address, now using the IPv4, the both of 0-255 four components, when the computer internal storage can be only 4 bytes. In the computer, the IP address is assigned to the card, each card has a unique IP address, if a computer has multiple network cards, the computer holds a number of different IP addresses on the same internal network, IP address can not be the same. The concept is similar to the IP address of the phone number, so the concept of identity.
  Because IP addresses are hard to remember, so the concept of creating a special domain name (Domain Name), in fact, to take the name of a character of IP, such as 163.com, sina.com and so on. There is a certain relationship between IP and domain name. If the IP address of the analogy to the ID number, then the domain name is your name.

  In fact, using only IP addresses in the network for data transmission, so before transmission, need to convert domain names into IP, this is done by specialized server called the DNS. Therefore, network programming, may be used to identify a domain name or IP device on the network.

The concept of a port
  for a plurality of programs can be run on a device, the concept design of artificial port (Port), the similar case is the internal extension number.
  A predetermined equipment 216, i.e. 65,536 ports, each corresponding to a unique (non-repeatable) program. Each network program, either the client or server side, corresponds to a specific port number or more. Because the operating system is multi-occupied between 0-1024, generally the actual port number 1024 after programming. Using port numbers, only one program can be found on a single device.

  So if you need a computer to establish a connection and then only need to know the IP address or domain name can be, but if you want a program on the computer to exchange data, then you must also know the port number used by the program.

Summary
      network programming is to use the IP address, or domain name, port number, and connected to the corresponding program on another computer, in accordance with a predetermined protocol (format data) to exchange data, and establish a connection to send the actual programming, the data received in the language level It has been achieved, the more work is done protocol design, coding and generate and parse data fills, and then converts the data into a logical structure to display or control logic.
      For starters, there is no contact or network programming programmers, network programming knowledge will feel involved very deep, very difficult, in fact, this is a misunderstanding, When your grammar familiar, in fact, the basic network programming has now been achieved abnormal simple.

Network Model Figure



Two, Socket Overview 



Three, UDP client code implementation 

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

/**
 * 客户端
 * 思路:
 * 1.建立可以实现UDP传输的Socket服务
 * 2.明确具体发送的数据
 * 3.通过Socket服务将具体的数据发送出去
 * 4.关闭服务
 * Created by yz on 2018/03/31.
 */
public class UdpSocketClient {
    // 写代码使用try注意地方,不要全部try 只需要可能会出现异常的代码才try
    // 整个try catch是比没有全部try catch 执行效率是降低的,底层有异常捕获机制
    public static void main(String[] args) throws SocketException {
        System.out.println("UDP发送端启动成功...");
        // 1.建立可以实现UDP传输的Socket服务
        DatagramSocket datagramSocket = new DatagramSocket();
        // 2.明确具体发送的数据
        String str = "注意啦,UDP发送的数据来啦!";
        byte[] bytes = str.getBytes();
        try {
            InetAddress serverIpAddress = InetAddress.getByName("192.168.230.1");
            // 3.通过Socket服务将具体的数据发送出去。 
            // 参数1字节数据 参数2字节长度 参数3发送端IP地址 参数4端口号
            DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, serverIpAddress, 9999);
            datagramSocket.send(datagramPacket);

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            // 4.关闭服务
            datagramSocket.close();
        }
    }
}

四、UDP服务器端代码实现 

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

/**
 * 服务器端
 * 思路:
 * 1.创建Socket服务,明确一个端口
 * 2.接收数据
 * 3.将其中的所需数据取出来 ip data 端口
 * 4.关闭服务
 * Created by yz on 2018/03/31.
 */
public class UdpSocketServer {
    public static void main(String[] args){
        System.out.println("UDP接受数据启动成功...");
        // 1.创建Socket服务,明确一个端口
        DatagramSocket datagramSocket = null;
        try {
            datagramSocket = new DatagramSocket(9999);
            // 2.定义接收数据格式
            byte[] buf = new byte[1024];
            DatagramPacket dp = new DatagramPacket(buf, buf.length);
            // 3.接收数据 并且有阻塞功能
            datagramSocket.receive(dp);
            // 获取IP地址
            String ip = dp.getAddress().getHostAddress();
            // 获取端口号
            int port = dp.getPort();
            // 数据
            String str = new String(dp.getData(), 0, dp.getLength());
            System.out.println(ip+",port:"+port+","+str);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            // 关闭服务
            datagramSocket.close();
        }
    }
}

五、TCP协议客户端 

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

/**
 * TCP协议客户端
 * 思路
 * 1.因为是面向连接,必须有连接才可以进行通讯
 * 2.在创建客户端时,就必须明确服务器端IP地址和端口号,不存在会抛异常
 * 3.一旦连接建立,就有了传输数据的通道,就可以在通道进行数据传输
 * 这个传输其实就是通过IO流实现的。
 * Created by yz on 2018/03/31.
 */
public class TcpSocketClient {
    public static void main(String[] args) throws IOException {
        Socket socket = null;
        OutputStream outputStream = null;
        try {
            // 连接服务器端 参数1服务器连接IP地址 参数2服务器端端口号,连接不上会抛异常
            socket = new Socket("192.168.230.1", 9999);
            // 获取Socket流中的输出流,将数据发送给服务器端
            outputStream = socket.getOutputStream();
            outputStream.write("TCP协议客户端来啦!".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            // 关闭连接
            outputStream.close();
            socket.close();
        }
    }
}

六、TCP协议服务器端 

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

/**
 * TCP协议服务器端
 * 思路
 * 1.创建socket服务器端服务,服务器端为了让客户端可以连接上,必须提供监听的端口号
 *  (服务器在哪一个机器部署的,IP地址就是哪个)
 * 2.获取客户端对象,通过客户端Socket流和对应的客户端进行通讯
 * 3.获取客户端的Socket流读取流
 * 4.读取数据并显示在服务器端
 * 5.关闭资源
 * Created by yz on 2018/03/31.
 */
public class TcpSocketServer {
    public static void main(String[] args) throws IOException {
        System.out.println("服务器端启动成功...");
        ServerSocket serverSocket = null;
        Socket accept = null;
        InputStream inputStream = null;
        try {
            // 1.创建socket服务器端
            serverSocket = new ServerSocket(9999);
            // 2.获取与客户端进行连接 有阻塞功能,如果没有客户端连接,一直等待。
            accept = serverSocket.accept();
            // 获取客户端IP
            String ip = accept.getInetAddress().getHostAddress();
            System.out.println("ip:"+ip);
            // 3.获取客户端的Socket流读取流
            inputStream = accept.getInputStream();
            byte[] buf = new byte[1024];
            int len = inputStream.read(buf);
            // 转换成字符串 每次读多少,从0开始,整个长度
            String str = new String(buf, 0, len);
            System.out.println(str);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            // 关闭连接
            inputStream.close();
            accept.close();
            serverSocket.close();
        }
    }
}

七、SockeTCP实现QQ聊天案例

实现案例:客户端和服务器端实现无线通讯,类似于QQ聊天(通讯连接不能断)

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

/**
 * TCP协议服务器端
 * 思路
 * 1.创建socket服务器端服务,服务器端为了让客户端可以连接上,必须提供监听的端口号
 *  (服务器在哪一个机器部署的,IP地址就是哪个)
 * 2.获取客户端对象,通过客户端Socket流和对应的客户端进行通讯
 * 3.获取客户端的Socket流读取流
 * 4.读取数据并显示在服务器端
 * 5.关闭资源
 * Created by yz on 2018/03/31.
 */
public class QQTcpSocketServer {
    public static void main(String[] args) throws IOException {
        System.out.println("服务器端启动成功...");
        // 1.创建socket服务器端
        ServerSocket serverSocket = new ServerSocket(9999);
        // 2.获取与客户端进行连接 有阻塞功能,如果没有客户端连接,一直等待。
        Socket accept = serverSocket.accept();
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            while (true){
                // 获取客户端IP
                String ip = accept.getInetAddress().getHostAddress();
                //System.out.println("ip:"+ip);
                // 3.获取客户端的Socket流读取流
                inputStream = accept.getInputStream();
                byte[] buf = new byte[1024];
                int len = inputStream.read(buf);
                // 转换成字符串 每次读多少,从0开始,整个长度
                String str = new String(buf, 0, len);
                System.out.println("客户端发送内容:"+str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            // 关闭连接
            inputStream.close();
            outputStream.close();
            accept.close();
            serverSocket.close();
        }
    }
}
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

/**
 * TCP协议客户端
 * 思路
 * 1.因为是面向连接,必须有连接才可以进行通讯
 * 2.在创建客户端时,就必须明确服务器端IP地址和端口号,不存在会抛异常
 * 3.一旦连接建立,就有了传输数据的通道,就可以在通道进行数据传输
 * 这个传输其实就是通过IO流实现的。
 * Created by yz on 2018/03/31.
 */
public class QQTcpSocketClient {
    public static void main(String[] args) throws IOException {
        System.out.println("客户端开始发送数据啦!");
            // 连接服务器端 参数1服务器连接IP地址 参数2服务器端端口号,连接不上会抛异常
            Socket socket = new Socket("192.168.230.1", 9999);
            InputStream inputStream = null;
            OutputStream outputStream = null;
            try{
                while (true){
                    // 获取Socket流中的输出流,将数据发送给服务器端
                    outputStream = socket.getOutputStream();
                    Scanner scanner = new Scanner(System.in);
                    System.out.println("给服务器端发送内容:");
                    String next = scanner.next();
                    outputStream.write(next.getBytes());
                    // 拿到服务器端回复的内容
                    inputStream = socket.getInputStream();
                    byte[] buf = new byte[1024];
                    int len = inputStream.read(buf);
                    // 转换成字符串 每次读多少,从0开始,整个长度
                    String str = new String(buf, 0, len);
                    System.out.println("收到服务器端回复内容:"+str);
                }
            }catch (Exception e){
            }finally {
                // 关闭连接
                inputStream.close();
                outputStream.close();
                socket.close();
            }
    }
}
山寨WEB服务器
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 目标:开发一个山寨WEB服务器
 * 1:支持多个浏览器访问
 * 2:如何提供服务(Socket)
 * 3: 如何返回响应(IO)
 * Created by yz on 2018/03/08.
 */
public class TomMonkey {

    private static int POST = 8080;
    /**
     * 程序启动入口
     * @param args
     */
    public static void main(String[] args) {
        // 动态设置服务器的端口
        int p = args.length>0 ? Integer.parseInt(args[0]):POST ;
        new TomMonkey().start(p);
    }

    /**
     * 服务启动方法
     */
    public void start(int port){
        try {
            ServerSocket ss = new ServerSocket(port);
            System.out.println("---------监听8080端口的服务器请求-----------");
            while (true){
                Socket socket = ss.accept();
                System.out.println("--------有客户端请求-------");
                // 创建一个线程池 设置100个线程
                ExecutorService pool = Executors.newFixedThreadPool(100);
                // 将任务提交给线程池去处理
                pool.submit(new HandlerRequestThread(socket));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

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

/**
 * 专门处理不同客户端请求的 多线程类
 * Created by yz on 2018/03/08.
 */
public class HandlerRequestThread implements Runnable{

    private  InputStream in = null;
    // 因为要涉及浏览器内容的输出,所以使用了PringStream 标准输出流
    private PrintStream out = null;

    // D:\MyWeb\ 好比web应用跟路径
    public static final String WEB_ROOT = "D:"+File.separator+"MyWeb"+File.separator;

    /**
     * 通过构造器获取Socket
     * 并通过Socket获取对客户端的输入和输出流
     * @param socket
     */
    public HandlerRequestThread(Socket socket) {
        try {
            in = socket.getInputStream();
            out = new PrintStream(socket.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 解析请求头,获得客户端请求的资源名称
     * @param in 输入流
     * @return 请求的资源名称
     */
    public String parseRequestHead(InputStream in) throws IOException {
        // 客户端发起请求会将一些请求数据包含在请求头中
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        // 请求头的第一行包含:请求的方式,请求的资源名称,请求的协议版本
        String headContent = br.readLine(); // GET /ttt.html HTTP/1.1
        System.out.println(headContent);
        String[] heads = headContent.split(" ");
        // 设置默认页面
        return heads[1].endsWith("/")? "test.jpg":heads[1];
    }

    /**
     * 获取请求信息
     * @param fileName
     * @throws IOException
     */
    public void getFile(String fileName) throws IOException {
        File file = new File(WEB_ROOT+fileName);
        System.out.println(file.toString());
        if(!file.exists()){
            sendError("404","您请求的资源["+fileName+"]不存在!");
            return;
        }else{
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
            byte[] content = new byte[(int) file.length()];
            int len = bis.read(content);
            // 告诉浏览器 本次操作成功
            out.println("HTTP/1.1 200 OK");
            out.println();
            // 写出数据
            out.write(content);
            out.flush();
            out.close();
        }
    }

    /**
     * 返回错误提示信息
     * @param errorNum
     * @param errorMsg
     */
    public void sendError(String errorNum,String errorMsg){
        StringBuilder sb = new StringBuilder();
        sb.append("<html><head><title>错误页面</title>");
        sb.append("<meta http-equiv='content-type' content='text/html;charset=utf-8'></head>");
        sb.append("<body><center><h1><font color='red'>"+errorNum+"</font></h1></center>");
        sb.append("<p>"+errorMsg+"</p></body></html>");
        out.println("HTTP/1.1 404 Not Found");
        out.println();
        out.print(sb.toString());
        out.flush();
        out.close();
    }
    /**
     * 线程体方法
     */
    public void run() {
        System.out.println("-------处理用户请求--------");
        try {
            String fileName = parseRequestHead(this.in);
            getFile(fileName);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


发布了43 篇原创文章 · 获赞 32 · 访问量 4万+

Guess you like

Origin blog.csdn.net/yz2015/article/details/79491030