网络通讯Socket

网络

在物理网络的基础上,建立抽象的连接

win + r, 输入 cmd

输入命令:

ipconfig

如果ping不通,要关闭防火墙

开始---搜索防火墙

Socket 通信

Socket - 插头

Socket - 网络套接字

通过 ip 地址,两台主机可以互相找到对象

在两台主机上,各选择一个端口号

端口是独占的,0到1024是一些常见服务的默认端口---http 80--https 443--ftp 21...5万以后,是系统保留端口用,来自动分配

我们选择端口要选择 1024到5万之间的端口号 

服务器端

被动等待客户端发起连接

ServerSocket 在服务器端,选择一个端口号, 在指定端口上等待客户端发起连接

ServerSocket ss = new ServerSocket(8000);

等待客户端发起连接,建立连接通道,并返回连接通道的服务器端插头对象

Socket s = ss.accept();

客户端

主动去连接服务器

Socket s = new Socket(ip, port);

取出双向的流

InputStream in = s.getInputStream();

OutputStream out = s.getOutputStream();

超时

socket.setSoTimeout(毫秒值)

设置接收数据,等待超时时长,超时会出现 SocketTimeoutException

实例:

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

public class Server1 {

public static void main(String[] args) throws Exception {
    ServerSocket ss = new ServerSocket(8000);
    System.out.println(
     "服务已经在 8000 端口上启动");
    //暂停等待客户端发起连接
    System.out.println("等待客户端连接");
    Socket s = ss.accept();
    System.out.println("客户端已连接");
    //从插头对象,获取输入流和输出流
    InputStream in = s.getInputStream();
    OutputStream out = s.getOutputStream();
    /*
     * 通信协议,通信流程,数据格式
     *
     *     服务器端:
     *       1. 接收 "hello"
     *       2. 发送 "world"
     */
    for (int i = 0; i < 5; i++) {
        char c = (char) in.read();
        System.out.print(c);
    }
    out.write("world".getBytes());
    out.flush(); //刷出内存缓存 
    s.close();//断开连接
    ss.close();//停止服务,释放端口
}
}

Client

package demo;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class Client1 {
public static void main(String[] args) throws Exception {
    Socket s = new Socket("旁边同学ip", 8000);
    InputStream in = s.getInputStream();
    OutputStream out = s.getOutputStream();
    /* 客户端:
     *    1. 发送 "hello"
     *    2. 接收 "world"
     */
    out.write("hello".getBytes());
    out.flush(); //刷出内存缓存
    for (int i = 0; i < 5; i++) {
        char c = (char) in.read();
        System.out.print(c);
    }
    s.close();
}
}

阻塞操作

ss.accept()

暂停,等待客户端发起连接

in.read()

对方不发送数据,暂停,死等数据

服务器端的线程模型

回声

客户端发送到服务器的数据,原封不动的发回客户端

EchoServer

package demo;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
 
public class EchoServer {
public void launch() {
    new Thread() {
        @Override
        public void run() {
           try {
              ServerSocket ss = new ServerSocket(8000);
              System.out.println("服务已在 8000 端口上启动");
              while(true) {
                 System.out.println("等待下一个客户端连接");
                 Socket s = ss.accept();
                 System.out.println("客户端已连接");
                 TongXinThread t = new TongXinThread(s);
                 t.start();
              }
           } catch (Exception e) {
              System.out.println(
               "无法在 8000 端口上启动服务,或服务已停止");
           }
        }
    }.start();
}
class TongXinThread extends Thread {
    Socket s;
    public TongXinThread(Socket s) {
        this.s = s;
    }
    @Override
    public void run() {
        /*
         * 通信协议,流程和格式
         * UTF-8编码的字符串,
         * 每段字符串末尾添加换行
         *
         * BR--ISR--网络输入流
         * PW--OSW--网络输出流
         */
        try {
           BufferedReader in =
            new BufferedReader(
            new InputStreamReader(
            s.getInputStream(), "UTF-8"));
           PrintWriter out =
            new PrintWriter(
            new OutputStreamWriter(
            s.getOutputStream(),"UTF-8"));
           String line;
           while((line = in.readLine()) != null) {
              out.println(line);
              out.flush();
           }
           //断开
        } catch (Exception e) {
           //断开
        }    
        System.out.println("一个客户端端已断开");     
    }
}



public static void main(String[] args) {

    EchoServer s = new EchoServer();

    s.launch();

}

}

EchoClient

package demo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.util.Scanner;

public class EchoClient {
public static void main(String[] args) throws Exception {
    Socket s = new Socket("找一个人启动服务器", 8000);
    BufferedReader in =
     new BufferedReader(
     new InputStreamReader(
     s.getInputStream(), "UTF-8"));
    PrintWriter out =
     new PrintWriter(
     new OutputStreamWriter(
     s.getOutputStream(),"UTF-8"));   
    while(true) {
        System.out.print("输入:");
        String str = new Scanner(System.in).nextLine();
        out.println(str);
        out.flush();
        String echo = in.readLine();
        System.out.println("回声:"+echo);
        System.out.println("-----------------");
    }
}
}

聊天室

ChatServer

package demo;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
 
public class ChatServer {
private ArrayList<TongXinThread> list =
        new ArrayList<>();
public void launch() {
    //启动服务线程
    new Thread() {
        @Override
        public void run() {
           try {
              ServerSocket ss = new ServerSocket(8000);
              System.out.println("聊天室服务器已启动");
              while(true) {
                 Socket s = ss.accept();
                 TongXinThread t =
                  new TongXinThread(s);
                 t.start();
              }
           } catch (Exception e) {
              System.out.println(
               "服务无法在 8000 端口上启动,或服务已经停止");
           }
        }
    }.start();
}

class TongXinThread extends Thread {
    Socket s;
    BufferedReader in;
    PrintWriter out;
    private String name;
    public TongXinThread(Socket s) {
        this.s = s;
    }
    public void send(String msg) {
        out.println(msg);
        out.flush();
    }
    public void sendAll(String msg) {
        synchronized (list) {
           for (TongXinThread t : list) {
              t.send(msg);
           }
        }
    }
    @Override
    public void run() {
        try {
           //UTF-8, 换行
           in = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8"));
           out = new PrintWriter(new OutputStreamWriter(s.getOutputStream(),"UTF-8"));            
           //接收客户端的昵称
           this.name = in.readLine();
           //把当前通信线程实例,加入集合
           synchronized (list) {
              list.add(this);
           }
           //发送欢迎信息
           send("欢迎进入激情聊天室");
           //群发上线消息
           sendAll(name+"进入了聊天室,在线人数:"+list.size());     
           String line;
           while((line = in.readLine()) != null) {
              sendAll(name+"说:"+line);
           }
           //断开
        } catch (Exception e) {
           //断开
        }
        //删除当前通信线程实例
        synchronized (list) {
           list.remove(this);
        }
        //群发离线消息
        sendAll(name+"离开了聊天室,在线人数:"+list.size());
    }
}





public static void main(String[] args) {

    ChatServer s = new ChatServer();

    s.launch();

}

}

ChatClient

package demo;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.LinkedList;
import java.util.Scanner;
 
public class ChatClient {
private Socket s;
private BufferedReader in;
private PrintWriter out;
private String name;
private LinkedList<String> list = new LinkedList<>();
private boolean flag; //开关

public void launch() {
    try {
        s = new Socket("192.168.21.61", 8000);
        in = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8"));
        out = new PrintWriter(new OutputStreamWriter(s.getOutputStream(),"UTF-8"));              
        //昵称
        System.out.print("起一个昵称: ");
        name = new Scanner(System.in).nextLine();
        out.println(name);
        out.flush();      
        //接收线程
        new Thread() {
           @Override
           public void run() {
              receive();
           }
        }.start();
        //输入线程
        new Thread() {
          @Override
           public void run() {
              input();
           }
        }.start();     
        //打印线程
        new Thread() {
           @Override
           public void run() {
              print();
           }
        }.start();    
    } catch (Exception e) {
        System.out.println("无法连接聊天室服务器");
        e.printStackTrace();
    }
}
protected void print() {
    while(true) {
        synchronized (list) {
           while (list.isEmpty() || flag) {
              try {
                 list.wait();
            } catch (InterruptedException e) {
           }
          }
           String msg = list.removeFirst();
           System.out.println(msg);
        }
    }
} 
protected void input() {
    System.out.println("按回车输入聊天内容"); 
    while(true) {
        new Scanner(System.in).nextLine();
        flag = true;//打开开关      
        System.out.print("输入聊天内容:");
        String s = new Scanner(System.in).nextLine();
        out.println(s);
        out.flush();    
        flag = false;//关闭开关
        //通知打印线程可以继续打印
        synchronized (list) {
        list.notify();
        }
    }
}
protected void receive() {
    try {
        String line;
        while((line = in.readLine()) != null) {
           synchronized (list) {
              list.add(line);
              //通知打印线程已经有数据可以打印了
              list.notify();
          }
        }
    } catch (Exception e) {
    }
    System.out.println("已经与服务器断开连接");
}
public static void main(String[] args) {
    ChatClient c = new ChatClient();
    c.launch();
}
}

猜你喜欢

转载自www.cnblogs.com/yunianzeng/p/12109804.html