今儿想看看进程间的通讯,信号量,PV操作什么的好TM费脑,索性就看其中的网络间进程通讯---socket编程,对这部分一直想敲敲代码,一直想不起来,因为不懂的太多了,每时每刻都是学不完的东西,今儿终于破个头儿。
本地的进程间通讯(IPC)有很多方式:
管道,,消息队列,信箱
同步(互斥量,条件变量,读写锁,信号量)
共享内存(匿名,具名)
在本地这些可以通过进程PID来唯一标示一个进程,网络编程中行不通,TCP/IP可以帮我们解决这个问题,网络层的“ip”可以唯一标示网络中的一台主机,而传输层的“协议+端口”可以唯一标示一台主机上的一个应用程序
使用TCP/IP协议的应用程序一般都是:UNIX BSD的套接字(socket)和UNIX System V的TLI(基本淘汰),所以现在几乎都是socket
参考文章:http://haohaoxuexi.iteye.com/blog/1979837 按着这个写了写,感觉很不错,层层深入 仅作为自己的学习笔记 理一理 条理一下体系
1 客户端写 服务器读
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Created by albert.bai on 2014/10/29.
*/
public class Server {
public static void main(String[] args) throws IOException {//所有异常都往外抛,为了方便而已
int port = 8899;
//定义一个ServerSocket监听在8899上 1024一下的端口不要用
ServerSocket serverSocket = new ServerSocket(port);
//尝试接受其他Socket的连接请求,server的accept方法应该是阻塞的
Socket socket = serverSocket.accept();
//跟客户端建立好连接后,我们就可以获取socket的InputStream,并从中读取客户端发过来的信息了
Reader reader = new InputStreamReader(socket.getInputStream());
char chars[] = new char[64];
int length;
StringBuffer stringBuffer = new StringBuffer();
while ((length=reader.read(chars))!=-1) {
stringBuffer.append(chars,0,length);
}
System.out.println("from client:"+stringBuffer);
reader.close();
socket.close();
serverSocket.close();
}
}
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.Socket;
/**
* Created by albert.bai on 2014/10/29.
*/
public class Client {
public static void main(String[] args) throws Exception {
String host ="127.0.0.1";//要连接的服务端IP 打开C:\Windows\System32\drivers\etc\hosts去看 原谅我还在用windows 囧
int port =8899;//要连接的服务器端对应的监听端口
Socket client = new Socket(host,port);//与服务器建立连接
Writer writer = new OutputStreamWriter(client.getOutputStream());
writer.write("Hello Server");
writer.flush();//写完后记得冲过去 如果写操作后对应的不是对应着输出流的关闭,而是其他阻塞式的操作,要flush一下,这样server才能接到数据
writer.close();
client.close();
}
}
切记关闭IO流和socket
2 server和client 同时读和写
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Created by albert.bai on 2014/10/29.
*/
public class Server {
public static void main(String[] args) throws IOException {//所有异常都往外抛,为了方便而已
int port = 8899;
//定义一个ServerSocket监听在8899上 1024一下的端口不要用
ServerSocket serverSocket = new ServerSocket(port);
//尝试接受其他Socket的连接请求,server的accept方法应该是阻塞的
Socket socket = serverSocket.accept();
//跟客户端建立好连接后,我们就可以获取socket的InputStream,并从中读取客户端发过来的信息了
Reader reader = new InputStreamReader(socket.getInputStream());
char chars[] = new char[64];
int length;
StringBuffer stringBuffer = new StringBuffer();
while ((length=reader.read(chars))!=-1) {
stringBuffer.append(chars,0,length);
}
System.out.println("from client:"+stringBuffer);
//读完了 写一句
Writer writer = new OutputStreamWriter(socket.getOutputStream());
writer.write("Hello Client");
writer.flush();
writer.close();
reader.close();
socket.close();
serverSocket.close();
}
}
上述代码在获取客户端发过来的信息后,发送一句信息给客户端,但也许永远都发不出去,除非客户端的socket关闭,因为接收信息是个阻塞式操作,这时length已经没什么效力了 因为永远接不到消息,这时我们用一个客户端发来的“eof”作为信息结束的标志来跳出循环
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.Socket;
/**
* Created by albert.bai on 2014/10/29.
*/
public class Client {
public static void main(String[] args) throws Exception {
String host ="127.0.0.1";//要连接的服务端IP 打开C:\Windows\System32\drivers\etc\hosts去看 原谅我还在用windows 囧
int port =8899;//要连接的服务器端对应的监听端口
Socket client = new Socket(host,port);//与服务器建立连接
Writer writer = new OutputStreamWriter(client.getOutputStream());
writer.write("Hello Server");
writer.write("eof");
writer.flush();//写完后记得冲过去 如果写操作后对应的不是对应着输出流的关闭,而是其他阻塞式的操作,要flush一下,这样server才能接到数据
//写完了读一个
Reader reader = new InputStreamReader(client.getInputStream());
char[] chars = new char[64];
int length;
StringBuffer sb = new StringBuffer();
String temp;
int index;
while ((length =reader.read(chars))!=-1) {
temp = new String(chars,0,length);
if ((index = temp.indexOf("eof"))!=-1) {
sb.append(temp.substring(0,index));
break;
}
sb.append(new String(chars,0,length));
}
writer.close();
client.close();
}
}
修改server代码
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Created by albert.bai on 2014/10/29.
*/
public class Server {
public static void main(String[] args) throws IOException {//所有异常都往外抛,为了方便而已
int port = 8899;
//定义一个ServerSocket监听在8899上 1024一下的端口不要用
ServerSocket serverSocket = new ServerSocket(port);
//尝试接受其他Socket的连接请求,server的accept方法应该是阻塞的
Socket socket = serverSocket.accept();
//跟客户端建立好连接后,我们就可以获取socket的InputStream,并从中读取客户端发过来的信息了
Reader reader = new InputStreamReader(socket.getInputStream());
char chars[] = new char[64];
String temp;
int length;
int index;
StringBuffer stringBuffer = new StringBuffer();
while ((length=reader.read(chars))!=-1) {
temp = new String(chars,0,length);
if((index = temp.indexOf("eof"))!=-1) {//遇到eof结束
stringBuffer.append(temp.substring(0,index));
break;
}
stringBuffer.append(temp);
}
System.out.println("from client:"+stringBuffer);
//读完了 写一句
Writer writer = new OutputStreamWriter(socket.getOutputStream());
writer.write("Hello Client");
writer.write("eof");
writer.flush();
writer.close();
reader.close();
socket.close();
serverSocket.close();
}
}
3 多个client 连接一个server
上面的代码在接受一个server请求后就不再接受其他请求,这样多不符合程序员高端,大气,上档次的气质 改!
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Created by albert.bai on 2014/10/29.
*/
public class Server {
public static void main(String[] args) throws IOException {//所有异常都往外抛,为了方便而已
int port = 8899;
//定义一个ServerSocket监听在8899上 1024一下的端口不要用
ServerSocket serverSocket = new ServerSocket(port);
while (true) {
//尝试接受其他Socket的连接请求,server的accept方法应该是阻塞的
Socket socket = serverSocket.accept();
//跟客户端建立好连接后,我们就可以获取socket的InputStream,并从中读取客户端发过来的信息了
Reader reader = new InputStreamReader(socket.getInputStream());
char chars[] = new char[64];
String temp;
int length;
int index;
StringBuffer stringBuffer = new StringBuffer();
while ((length = reader.read(chars)) != -1) {
temp = new String(chars, 0, length);
if ((index = temp.indexOf("eof")) != -1) {//遇到eof结束
stringBuffer.append(temp.substring(0, index));
break;
}
stringBuffer.append(temp);
}
System.out.println("from client:" + stringBuffer);
//读完了 写一句
Writer writer = new OutputStreamWriter(socket.getOutputStream());
writer.write("Hello Client");
writer.write("eof");
writer.flush();
writer.close();
reader.close();
socket.close();
}
}
}
设置一个死循环,这样在处理完一个请求后就可以处理下一个请求,但这样和client请求时同步进行的,当请求过多时就会丢掉一些请求,还是不符合我们的气质啊 改!!
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Created by albert.bai on 2014/10/29.
*/
public class Server {
public static void main(String[] args) throws IOException {//所有异常都往外抛,为了方便而已
int port = 8899;
//定义一个ServerSocket监听在8899上 1024一下的端口不要用
ServerSocket serverSocket = new ServerSocket(port);
while (true) {
//尝试接受其他Socket的连接请求,server的accept方法应该是阻塞的
Socket socket = serverSocket.accept();
new Thread(new Task(socket)).start();
}
}
static class Task implements Runnable {
private Socket socket;
public Task(Socket socket) {
this.socket = socket;
}
public void run() {
try {
handleSocket();
} catch (Exception e) {
e.printStackTrace();
}
}
private void handleSocket() throws Exception {
//跟客户端建立好连接后,我们就可以获取socket的InputStream,并从中读取客户端发过来的信息了
Reader reader = new InputStreamReader(socket.getInputStream());
char chars[] = new char[64];
String temp;
int length;
int index;
StringBuffer stringBuffer = new StringBuffer();
while ((length = reader.read(chars)) != -1) {
temp = new String(chars, 0, length);
if ((index = temp.indexOf("eof")) != -1) {//遇到eof结束
stringBuffer.append(temp.substring(0, index));
break;
}
stringBuffer.append(temp);
}
System.out.println("from client:" + stringBuffer);
//读完了 写一句
Writer writer = new OutputStreamWriter(socket.getOutputStream());
writer.write("Hello Client");
writer.write("eof");
writer.flush();
writer.close();
reader.close();
socket.close();
}
}
}
这样我们就可以采用异步的方式处理请求了,在每个请求发过来后开启一个线程去跑就好了 现在我们换成BufferReader来一次读一行数据
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Created by albert.bai on 2014/10/29.
*/
public class Server {
public static void main(String[] args) throws IOException {//所有异常都往外抛,为了方便而已
int port = 8899;
//定义一个ServerSocket监听在8899上 1024一下的端口不要用
ServerSocket serverSocket = new ServerSocket(port);
while (true) {
//尝试接受其他Socket的连接请求,server的accept方法应该是阻塞的
Socket socket = serverSocket.accept();
new Thread(new Task(socket)).start();
}
}
static class Task implements Runnable {
private Socket socket;
public Task(Socket socket) {
this.socket = socket;
}
public void run() {
try {
handleSocket();
} catch (Exception e) {
e.printStackTrace();
}
}
private void handleSocket() throws Exception {
//跟客户端建立好连接后,我们就可以获取socket的InputStream,并从中读取客户端发过来的信息了
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String temp;
int index;
StringBuffer stringBuffer = new StringBuffer();
while ((temp = bufferedReader.readLine())!=null) {
System.out.println(temp);
if ((index = temp.indexOf("eof")) != -1) {//遇到eof结束
stringBuffer.append(temp.substring(0, index));
break;
}
stringBuffer.append(temp);
}
System.out.println("from client:" + stringBuffer);
//读完了 写一句
Writer writer = new OutputStreamWriter(socket.getOutputStream());
writer.write("Hello Client");
writer.write("eof\n"); //换行符啊 上面可是readline啊
writer.flush();
writer.close();
bufferedReader.close();
socket.close();
}
}
}
readline在读到换行符或者对应流的结束符才会认为我已经读了一行了 切记flush一下 这样才会从缓冲区里写入
对应的client
import java.io.*;
import java.net.Socket;
/**
* Created by albert.bai on 2014/10/29.
*/
public class Client {
public static void main(String[] args) throws Exception {
String host ="127.0.0.1";//要连接的服务端IP 打开C:\Windows\System32\drivers\etc\hosts去看 原谅我还在用windows 囧
int port =8899;//要连接的服务器端对应的监听端口
Socket client = new Socket(host,port);//与服务器建立连接
Writer writer = new OutputStreamWriter(client.getOutputStream());
writer.write("Hello Server");
writer.write("eof\n");
writer.flush();//写完后记得冲过去 如果写操作后对应的不是对应着输出流的关闭,而是其他阻塞式的操作,要flush一下,这样server才能接到数据
//写完了读一个
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
StringBuffer sb = new StringBuffer();
String temp;
int index;
while ((temp =bufferedReader.readLine())!=null) {
if ((index = temp.indexOf("eof"))!=-1) {
sb.append(temp.substring(0,index));
break;
}
sb.append(temp);
}
writer.close();
bufferedReader.close();
client.close();
}
}
4 设置Time-out
import java.io.*;
import java.net.Socket;
import java.net.SocketTimeoutException;
/**
* Created by albert.bai on 2014/10/29.
*/
public class Client {
public static void main(String[] args) throws Exception {
String host ="127.0.0.1";//要连接的服务端IP 打开C:\Windows\System32\drivers\etc\hosts去看 原谅我还在用windows 囧
int port =8899;//要连接的服务器端对应的监听端口
Socket client = new Socket(host,port);//与服务器建立连接
Writer writer = new OutputStreamWriter(client.getOutputStream());
writer.write("Hello Server");
writer.write("eof\n");
writer.flush();//写完后记得冲过去 如果写操作后对应的不是对应着输出流的关闭,而是其他阻塞式的操作,要flush一下,这样server才能接到数据
//写完了读一个
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
client.setSoTimeout(10*1000);//防止一直没有读到数据 超时抛出异常 单位毫秒
StringBuffer sb = new StringBuffer();
String temp;
int index;
try {
while ((temp = bufferedReader.readLine()) != null) {
if ((index = temp.indexOf("eof")) != -1) {
sb.append(temp.substring(0, index));
break;
}
sb.append(temp);
}
}catch (SocketTimeoutException e) {
System.out.println("数据读取超时");
e.printStackTrace();
}
writer.close();
bufferedReader.close();
client.close();
}
}
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
/**
* Created by albert.bai on 2014/10/29.
*/
public class Server {
public static void main(String[] args) throws IOException {//所有异常都往外抛,为了方便而已
int port = 8899;
//定义一个ServerSocket监听在8899上 1024一下的端口不要用
ServerSocket serverSocket = new ServerSocket(port);
while (true) {
//尝试接受其他Socket的连接请求,server的accept方法应该是阻塞的
Socket socket = serverSocket.accept();
new Thread(new Task(socket)).start();
}
}
static class Task implements Runnable {
private Socket socket;
public Task(Socket socket) {
this.socket = socket;
}
public void run() {
try {
handleSocket();
} catch (Exception e) {
e.printStackTrace();
}
}
private void handleSocket() throws Exception {
//跟客户端建立好连接后,我们就可以获取socket的InputStream,并从中读取客户端发过来的信息了
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String temp;
int index;
StringBuffer stringBuffer = new StringBuffer();
socket.setSoTimeout(10*1000);
try {
while ((temp = bufferedReader.readLine()) != null) {
System.out.println(temp);
if ((index = temp.indexOf("eof")) != -1) {//遇到eof结束
stringBuffer.append(temp.substring(0, index));
break;
}
stringBuffer.append(temp);
}
System.out.println("from client:" + stringBuffer);
}catch (SocketTimeoutException e) {
System.out.println("数据读取超时");
e.printStackTrace();
}
//读完了 写一句
Writer writer = new OutputStreamWriter(socket.getOutputStream());
writer.write("Hello Client");
writer.write("eof\n"); //换行符啊 上面可是readline啊
writer.flush();
writer.close();
bufferedReader.close();
socket.close();
}
}
}
满满的成就感