java中Socket编程
TCP
- 面向连接 和打电话一样,必须要建立通信。
- 可靠性 不会丢失文件。
- 顺序,无差错。
Socket
套接字
网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个
Socket
一个Socket由一个IP地址和一个端口号唯一确定。
cmd netstat -ano
IP
确定唯一的一台电脑地址
端口
确定电脑上唯一的应用程序
0~1023被系统保留。
1024-65535 每个端口只允许一个程序访问。
代码步骤
1. 服务端 创建ServerSocketServerSocket只用来等待客户端连接,不能通过他进行交互。
2. 等待客户端链接
Socket socket = ServerSocket.accept();等待客户端连接,返回一个Socket实例
3. 客户端通过Sockek进行连接Socket socket = new Socket(host,port);
4. 通过两边的socket获取流进行输入输出。
注意
1. 程序开过一次后,会占用端口,注意关闭程序,否则不能运行第二次。
2. 每个阻塞式方法都必须存在一条新线程中,否则阻塞后其他方法无法执行,如等待客
户端连接 accept() , 键盘输入 input.next() ,读数据while((len=is.read(buf))!=-1) 等操作都会阻塞。
3. 启动新线程一般放在最上面,不能放在阻塞式方法的后面,否则执行不了,或者出现问题
//服务端
public class Server2 extends Thread {// 能同时连接多台电脑ServerSocket server;List<Socket> list = new ArrayList<>();public Server2() {try {server = new ServerSocket(8888);} catch (IOException e) {e.printStackTrace();}}@Overridepublic void run() {super.run();while (true) {try {// 每次循环到这里 都会再次等待客户端连接Socket socket = server.accept();// 添加所有链接的用户System.out.println(socket.getInetAddress().getHostAddress()+ "连上了");sendMessageToAllPC(socket.getInetAddress().getHostAddress()+ "上线了");list.add(socket);new ReaderThread(socket).start();// 开个线程} catch (IOException e) {}}}// 写的方法public void sendMessageToAllPC(String msg) {for (Socket socket : list) {if (socket != null && socket.isConnected()) {OutputStream os;try {os = socket.getOutputStream();os.write(msg.getBytes());os.flush();// 千万不要关} catch (IOException e) {}}}}// 专用读的线程class ReaderThread extends Thread {InputStream is;public ReaderThread(Socket socket) {try {is = socket.getInputStream();} catch (IOException e) {}}// 只做读操作@Overridepublic void run() {// 读了你的消息,转发给其他所有用户byte[] buf = new byte[1024];int len = 0;try {while ((len = is.read(buf)) != -1) {sendMessageToAllPC(new String(buf, 0, len));}} catch (IOException e) {}}}
}//客户端public class Client2 extends Thread {Socket socket;String name;public Client2(String name) {this.name = name;try {socket = new Socket("192.168.18.250", 8888);} catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}@Overridepublic void run() {// 读线程new ReaderThread().start();// 写操作try {Scanner input = new Scanner(System.in);String speak = null;// 写的流OutputStream os = socket.getOutputStream();do {speak = input.next();os.write((name + ":" + speak).getBytes());os.flush();} while (!speak.equals("bye"));input.close();socket.close();} catch (IOException e) {e.printStackTrace();}}class ReaderThread extends Thread {@Overridepublic void run() {try {InputStream is = socket.getInputStream();int len = 0;byte[] buf = new byte[1024];while ((len = is.read(buf)) != -1) {System.out.println(new String(buf, 0, len));}} catch (IOException e) {e.printStackTrace();}}}}
UDP
- 面向无连接,没有服务端与客户端,和发短信一样,分为发送方和接收方。
- UDP有大小限制,每个数据报只有64KB大小,报文。
- 不可靠协议,数据不一定会到达,也不一定是按顺序到达。
广播
广播地址是192.168.*.255
发送步骤
// 1.建立发送的主机地址
SocketAddress address = new InetSocketAddress(host, port);
// 2.建立数据报
// 长度一定要注意 转字节获取长度DatagramPacket dp = new DatagramPacket(msg.getBytes(),
msg.getBytes().length, address);// 2. 发送数据报socket.send(dp);
public class UDPUtils extends Thread {// 收发数据// 端口号DatagramSocket socket;public UDPUtils(int port) {// 我在本机器上,监听该端口try {socket = new DatagramSocket(port);} catch (SocketException e) {e.printStackTrace();}}// 发送数据报// 1. 对方端口// 2. 对方ip地址// 3. 数据public void sendMessage(String host, int port, String msg)throws IOException {// 1.建立发送的主机地址SocketAddress address = new InetSocketAddress(host, port);// 2.建立数据报// 长度一定要注意 转字节获取长度DatagramPacket dp = new DatagramPacket(msg.getBytes(),msg.getBytes().length, address);// 2. 发送数据报socket.send(dp);}// 收报@Overridepublic void run() {// 一个包 如果缓冲区不够,就丢失了byte[] buf = new byte[65535];DatagramPacket packet = new DatagramPacket(buf, buf.length);while (true) {try {// 阻塞式socket.receive(packet);// 收到了数据报// 拆包String msg = new String(packet.getData(), 0, packet.getLength());System.out.println(msg);} catch (IOException e) {e.printStackTrace();}}}
}//mian方法类public class Test {/*** TCP 协议 Socket 用来连接 ServerSocket 服务端 用来监听客户端连接 accept() 阻塞并等待客户端的链接* * 通过Socket的getInputStream和getOutputStream来获取流进行通信* * * Tcp特点 保持连接状态 不会丢失数据 并且数据顺序到达* * * @param args*/public static void main(String[] args) {UDPUtils utils = new UDPUtils(7777);utils.start();Scanner input = new Scanner(System.in);int index = 0;while (index++ < 5) {String msg = input.next();// 发送给谁try {utils.sendMessage("192.168.18.255", 7777, msg);} catch (IOException e) {e.printStackTrace();}}input.close();}}