java网络编程day02
双向传输数据
客户端代码
public class Clinet {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
os.write("你好,服务器端!".getBytes());
//作为结束标志标志
socket.shutdownOutput();
byte[] read = new byte[1024];
int readLine = 0;
while ((readLine = is.read(read)) != -1) {
System.out.println(new String(read, 0, readLine));
}
is.close();
os.close();
//socket.close();is和os关闭时就会关闭
}
}
服务端代码
public class Server {
public static void main(String[] args) throws IOException {
//建立端口监听
ServerSocket serverSocket = new ServerSocket(9999);
//等待链接
Socket socket = serverSocket.accept();
//获取Socket输入输出流
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
byte[] read = new byte[1024];
int readLine = 0;
//从网络管道中读取数据
while ((readLine = is.read(read)) != -1) {
System.out.println(new String(read, 0, readLine));
}
System.out.println("读入完毕");
os.write("你好客户端!".getBytes());
//socket.shutdoenOutput方法用来作为结束输出标志,如果不写会导致程序不知道什么时候读取完毕
//socket.shutdownOutput();由于此程序后面没有内容,直接关流也能其同样的作用
System.out.println("写入完毕");
is.close();
os.close();
//socket.close();关闭socket返回的输入输出流时,socket也会被关掉,所以如果后面还要使用socket就不能用关流结束输出
serverSocket.close();
}
}
总结:
- 关闭socket对象返回的OutputStream/InputStream流时将同时关闭关联的套接字。
- 输出需要添加结束标志符,对字节输出流而言只能将流关闭,或者使用shutdownOutput方法暂时终止
- 一旦将流关闭,后面将没法使用socket对象,除非重新获取socket对象
使用字符流完成双向数据传输
客户端
public class Clinet {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
InputStreamReader isr = new InputStreamReader(socket.getInputStream());
OutputStreamWriter osw = new OutputStreamWriter(socket.getOutputStream());
BufferedReader bufferedReader = new BufferedReader(isr);
BufferedWriter bufferedWriter = new BufferedWriter(osw);
bufferedWriter.write("你好服务端");
//必须刷新否则写入失败
bufferedWriter.flush();
//结束输出标记,可以用 osw.newLine() 替代,替代以后读取也必须用readLine读取
socket.shutdownOutput();
char[] read = new char[1024];
int readLine = 0;
while ((readLine = bufferedReader.read(read)) != -1) {
System.out.println(new String(read, 0, readLine));
}
bufferedReader.close();
bufferedWriter.close();
}
服务器端
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9999);
Socket socket = serverSocket.accept();
OutputStreamWriter osw = new OutputStreamWriter(socket.getOutputStream());
InputStreamReader isr = new InputStreamReader(socket.getInputStream());
BufferedWriter bufferedWriter = new BufferedWriter(osw);
BufferedReader bufferedReader = new BufferedReader(isr);
char[] read = new char[1024];
int readLine = 0;
while ((readLine = bufferedReader.read(read)) != -1) {
System.out.println(new String(read, 0, readLine));
}
bufferedWriter.write("你好客户端");
bufferedWriter.flush();
//socket.shutdownOutput();
bufferedWriter.close();
//socket.close();
serverSocket.close();
}
总结:
- 在字符流使用中可以使用newLine方法作为结束标识,但是想对应的读取的时候也必须用readLine方法读取
- 使用字符流写入时必须使用flush刷新流,否则写入失败抛出异常
- 关流迟出现的流后关准没错
shutdownOutput用处
禁用此套接字的输出流。对于 TCP 套接字,任何先前写入的数据都将按照 TCP 的正常连接终止顺序发送。如果在套接字上调用 shutdownOutput() 后写入套接字输出流,则该流将引发 IOException。
什么意思?
- 在客户端或者服务端通过socket.shutdownOutput()都是单向关闭的,即关闭客户端的输出流并不会关闭服务端的输出流,所以是一种单方向的关闭流;
- 通过socket.shutdownOutput()关闭输出流,但socket仍然是连接状态,连接并未关闭
- 如果直接关闭输入或者输出流,即:in.close()或者out.close(),会直接关闭socket
TCP网络通信编程不为人知的秘密
- 当客户端连接到服务器端后,实际上客户端也是通过一个端口和服务器进行通讯的,这个端口是TCP/IP来分配的,是不确定的,随机的
- windows下可以使用netstat命令验证端口号
UDP编程
- 没有明确的服务器端和客户端,眼变成数据的发送端和接受端
- 数据接受和发送是通过DatagramPacket对象(包含数据ip和端口)完成的
- 将数据封装成DaragramPacket对象传输(装包/拆包)
- 可以指定在哪个端口接受数据