前言
首先,说一件无关的事情,萧鼎的诛仙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
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还是有点复杂的,蛋疼