前景
由于最近有一个课设里面我是负责socket+JDBC的,所以就来学学java的socket,顺便熟悉几种流,由于我之前的进度还在数据结构红黑树和JVM那,所以先跳过来看看
socket基础
由于socket通信不难的,就直接编程了,首先是基于最简单InputStream,outputStream,字节流
服务器:
package byteserver;
import java.io.*;
import java.net.*;
public class Server
{
public void server()
{
try
{
ServerSocket server = new ServerSocket(55000);
Socket socket = server.accept();
try
{
// 从socket中获得输入输出流
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
// 输入流读进byte数组里面
byte[] bytes = new byte[1024];
in.read(bytes);
System.out.println("message from client"+new String(bytes));
}
finally
{
socket.close();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
Server server = new Server();
server.server();
}
}
客户端
package byteclient;
import java.io.*;
import java.net.*;
import java.lang.StringBuilder;
public class Clinet
{
public void client()
{
try
{
Socket socket = new Socket("127.0.0.1",55000);
try
{
OutputStream out = socket.getOutputStream();
InputStream in = socket.getInputStream();
out.write("Hello, this is client".getBytes());
out.flush();
}
finally
{
socket.close();
}
}
catch(IOException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
Clinet client = new Clinet();
client.client();
}
}
这是最简单的例子,做的事情也很少,仅仅是客户端发,服务端收信息
客户端发送完,服务器响应消息
客户端发送完了自己的信息之后,关闭输出流,等待服务器的回应信息,之后再关闭连接
服务器
package byteserver;
import java.io.*;
import java.net.*;
public class Server
{
public void server()
{
try
{
ServerSocket server = new ServerSocket(55000);
Socket socket = server.accept();
try
{
// 从socket中获得输入输出流
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
// 输入流读进byte数组里面
byte[] bytes = new byte[1024];
in.read(bytes);
System.out.println("message from client"+new String(bytes));
// 服务器返回成功消息
out.write("from server:success".getBytes());
out.flush();
}
finally
{
socket.close();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
Server server = new Server();
server.server();
}
}
客户机
package byteclient;
import java.io.*;
import java.net.*;
import java.lang.StringBuilder;
public class Clinet
{
public void client()
{
try
{
Socket socket = new Socket("127.0.0.1",55000);
try
{
OutputStream out = socket.getOutputStream();
InputStream in = socket.getInputStream();
out.write("Hello, this is client".getBytes());
out.flush();
// 客户端发送完了,关闭输出流
socket.shutdownOutput();
byte[] bytes = new byte[1024];
StringBuilder builder = new StringBuilder();
in.read(bytes);
System.out.println("message from server: "+new String(bytes));
}
finally
{
socket.close();
}
}
catch(IOException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
Clinet client = new Clinet();
client.client();
}
}
这种半关闭的状态,HTTP的短连接和短链接很像,请求一次之后就断开,好奇HTTP的长连接怎么搞的,不过我不是网络编程,所以不去深入,主要是借助它了解流的形式的
聊天交互
刚才我们看到的都是一次性的交互,那么如果我要聊天呢?我发一句,你发一句的那种。
package client;
import java.net.Socket;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.IOException;
import java.util.Scanner;
import java.io.PrintWriter;
public class Client
{
public void server()
{
try
{
Socket socket = new Socket("127.0.0.1", 55000);
try
{
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
PrintWriter writer = new PrintWriter(new OutputStreamWriter(out, "UTF-8"),true);
Scanner keyboard_in = new Scanner(System.in, "UTF-8");
Scanner stream_in = new Scanner(in, "UTF-8");
boolean flag = false;
while(flag == false && keyboard_in.hasNextLine())
{
// 键盘读取需要发送的内容
String keyboard_indata = keyboard_in.nextLine();
if (keyboard_indata.equals("end"))
{
flag = true;
}
//传递给OutputStreamWriter
writer.println(keyboard_indata);
// 输入流中接受服务器的信息
String indata = stream_in.nextLine();
System.out.println("服务器的消息:"+indata);
}
}
finally
{
socket.close();
}
}
catch(IOException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
Client client = new Client();
client.server();
}
}
服务器
package server;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.io.IOException;
public class Server
{
public void service()
{
try
{
ServerSocket server = new ServerSocket(55000);
Socket socket = server.accept();
System.out.println(socket.getInetAddress()+"地址已经连接");
try
{
OutputStream out = socket.getOutputStream();
InputStream in = socket.getInputStream();
PrintWriter writer = new PrintWriter(new OutputStreamWriter(out, "UTF-8"),true);
Scanner keyboard_in = new Scanner(System.in);
Scanner stream_in = new Scanner(socket.getInputStream());
while(stream_in.hasNextLine())
{
String indata = stream_in.nextLine();
System.out.println("客户端消息:"+indata);
String keyboard_indata = keyboard_in.nextLine();
writer.println(keyboard_indata);
}
}
finally
{
socket.close();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
Server server = new Server();
server.service();
}
}
聊天倒是次要的,本文主要的是流
所有的流都有一个共同的祖先InputStream,它是一个字节流,当我们需要处理字符串和数字的时候就需要用到它的子类。
PrintWriter writer = new PrintWriter(new OutputStreamWriter(out, "UTF-8"),true);
Scanner keyboard_in = new Scanner(System.in);
Scanner stream_in = new Scanner(socket.getInputStream());
PritWriter 这个类比较强大,它能基于文本的输出,以文本的格式打印字符串和数字,它的里面封装了一个OutputStreamWriter,这是一个写出器,作用是将字符流转换成字节流,意思就是说 文本->字符流->字节流,这样的一个顺序(PS,虽然PrintWriter的Print之类的方法像是打印,实际上只是输出给里面的OutputStreamWriter),最终socket发出的是还是字节流,Scanner这个类,能接收各种形式的流,所以直接包装字节流是没有问题的。
注意循环条件,服务器里面的条件是 有输入流,客户端的条件是键盘输入
总结
由于笔者只是临时学socket,所以并不深入,流也是学了一点点,日后还要系统的学习一下流的操作,今天只是做一个简单的了解