Java实现简单的socket通信

前言

首先,说一件无关的事情,萧鼎的诛仙2更新了,这一等就是一年啊,今天中午思考去阿里用神马花名的时候想起来google一下诛仙二,结果50多章都没看过,555,没忍住一下午全用来看小说了,罪过罪过

其次,就是今天学习了一下java如何实现socket通信,感觉难点反而是在io上,因为java对socket封装已经很完善了


参考

学习了一篇博客,写的不错,推荐给大家: http://cs.lmu.edu/~ray/notes/javanetexamples/#capitalize


代码

今天代码花了整个晚上调试,主要原因是io的flush问题和命令行下如何运行具有package的类,不过最后问题基本都解决了,把代码贴出来供大家参考

server

package socket;

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

public class TcpServer {
    public static void main(String[] args) throws Exception {
        ServerSocket server = new ServerSocket(9091);
        try {
            Socket client = server.accept();
            try {
                BufferedReader input =
                        new BufferedReader(new InputStreamReader(client.getInputStream()));
                boolean flag = true;
                int count = 1;

                while (flag) {
                    System.out.println("客户端要开始发骚了,这是第" + count + "次!");
                    count++;
                    
                    String line = input.readLine();
                    System.out.println("客户端说:" + line);
                    
                    if (line.equals("exit")) {
                        flag = false;
                        System.out.println("客户端不想玩了!");
                    } else {
                        System.out.println("客户端说: " + line);
                    }

                }
            } finally {
                client.close();
            }
            
        } finally {
            server.close();
        }
    }
}

client

package socket;

import java.io.*;
import java.net.*;
import java.util.Scanner;

public class TcpClient {
    public static void main(String[] args) throws Exception {
        Socket client = new Socket("127.0.0.1", 9091);
        try {
            PrintWriter output =
                    new PrintWriter(client.getOutputStream(), true);
            Scanner cin = new Scanner(System.in);
            String words;

            while (cin.hasNext()) {
                words = cin.nextLine();

                output.println(words);

                System.out.println("写出了数据: " + words);
            }

            cin.close();
        } finally {
            client.close();
        }
    }
}


Server绑定ip

用c写socket的时候,struct sockaddr_in 结构体是可以指定sin_addr.s_addr的,也就是可以指定ip地址,为什么会有这种需求呢,例如我的网络链接是这样的:



我可能只想绑定eth0这个网卡的ip地址,因为我的lo和wlan0都可能在用一端口做了nginx的虚拟主机,因此在服务器端开启ServerSocket的时候,有指定ip的需求


方案

ServerSocket的一个构造函数如下:

public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException

参数:
  • port - 本地 TCP 端口
  • backlog - 侦听 backlog
  • bindAddr - 要将服务器绑定到的 InetAddress

因为InetAddress无构造函数,我在这里纠结了好一段时间,查看stackoverflow上,可以使用InetAddress的getByName方法

示例代码

InetAddress bindip = InetAddress.getByName("192.168.1.168");

ServerSocket server = new ServerSocket(9091, 0, bindip);


并发访问

服务器端通过增加多线程来同时处理多个客户端的请求,其实实现还是很水的,毕竟java对多线程封装也足够好了,我是在Server服务器端用一个内部类实现了Runnable接口,在run方法里处理客户端的请求,将数据打印出来

server代码

package capitalsocket;

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

public class CapitalizeServer {
    private static int clientNum = 0;

    public static void main(String args[]) throws Exception {
        ServerSocket listener = new ServerSocket(9898, 0, InetAddress.getByName("192.168.1.168"));
        try {
            while (true) {
                Capitalizer multip = new Capitalizer(listener.accept(), CapitalizeServer.clientNum ++);
                Thread t = new Thread(multip);
                t.start();
            }
        } finally {
            listener.close();
        }
    }

    private static class Capitalizer implements Runnable {
        private Socket client;
        private int id;

        public Capitalizer(Socket s, int id) {
            this.client = s;
            this.id = id;
        }

        public void run() {
            try {
                BufferedReader input =
                        new BufferedReader(new InputStreamReader(this.client.getInputStream()));
                
                while (true) {
                    String data = input.readLine();
                    
                    if (data.equals("bye")) {
                        System.out.println("当前第" + this.id + "个客户端度不想玩了!");
                        break;
                    } else {
                        System.out.println("当前第" + this.id + "个客户端说:" + data);
                    }
                }

            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    this.client.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

client代码

客户端代码基本没变,增加了一个退出操作

package capitalsocket;

import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class CapitalizeClient {
    public static void main(String[] args) throws Exception {
        Socket client = new Socket("192.168.1.168", 9898);
        try {
            PrintWriter output = new PrintWriter(client.getOutputStream(), true);
            Scanner cin = new Scanner(System.in);
            String words;

            while (cin.hasNext()) {
                words = cin.nextLine();
                output.println(words);
                
                if (words.equals("bye")) {
                    break;
                }
                
                // 每写一次数据需要sleep一会
                Thread.sleep(3000);
            }

            cin.close();
        } finally {
            client.close();
        }
    }
}


吐槽

java的io还是有点复杂的,蛋疼
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值