基于TCP的Socket通信
TCP 是一种 流协议,以流为单位进行数据传输 。
什么是长连接?
长连接可以实现当服务端与客户端连接成功后连续地传输数据,在这 个过程中,连接保持开启的状态,数据传输完毕后连接不关闭 。
长连接是指建立 Socket 连 接后,无论是否使用这个连接,该连接都保持连接的状态 。
什么是短连接?
短连接是当服务端与客户端连接成功后开始传输数据,数据传输完毕 后则连接立即关闭,如果还想再次传输数据,
则需要再创建新的连接进行数据传输 。
什么是连接?
在 TCP/IP 中, 连接可以认为是服务端与客户端确认彼 此都存在的过程 。
由于 UDP 是无连接协议,也就是服务端与客户端 没有确认彼此都存在的握手过程,因此在 UDP 里面不存在长连接与短连接的概念 。
长连接的优缺点
优点: 除了第一次之外,客户端不需要每次传输数据时都先与服务端进行握手,这样就减少了握手确认的时间,直接传输数据,提高程序运行效率 。
缺点: 在服务端保存多个 Socket对象,大量占用服务器资源。
短连接的优缺点
优点 : 在服务端不需要保存多个 Socket对象,降低内存占用率 。
缺点 : 每次传输数据前都要重新创建连接,也就是每次都要进行 3 次握手,增加处理的时间 。
验证 ServerSocket 类的 accept()方法具有阻塞特性
ServerSocket类的作用是创建 Socket (套接字)的服务端,而 Socket类的作用是创建 Socket 的客户端 。 在代码层面使用的方式就是使用 Socket类去连接 ServerSocket类,也就是客户端要主动连接服务端 。
ServerSocket 类中的 public Socket accept()方法的作用是侦听并接受此套接字的连接 。
此方法在连接传人之前一直阻塞。
有客户端连接到服务 端时就不再出现阻塞 了,服务端的程序会继续运行 。
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class CreateWebServer {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(7777) ;
Socket socket= serverSocket.accept() ;
InputStream inputStream = socket.getInputStream() ;
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader) ;
String getString = "";
while (!"".equals(getString = bufferedReader.readLine())) {
System.out.println(getString);
OutputStream outputStream = socket.getOutputStream();
outputStream.write("HTTP/1.1 200 OK\r\n\r\n".getBytes());
outputStream.write("<html><body><a href='http://www.baidu.com'> i am baidu.com welcome you ! </a> </body></html> ".getBytes());
outputStream.flush();
inputStream.close();
outputStream.close();
socket.close ();
serverSocket.close();
}
}
}
在 IE 浏览器地址栏中输入以下网址 : http://127.0.0.1:7777/
验证 Socket 中 lnputStream 类的 read()方法也具有阻塞特性
除了 ServerSocket类 中的 accept()方法具 有阻塞特性外, InputStream类中的 read()方法 也同样具有阻塞特性 。
read()方法阻塞 的原因是客户端并未发送数据到服务端,
服务端一 直在尝试读取从客户端传递过来的数据,
因为客户端从未发送数据给服务端,所以服务端一直在阻塞。
客户端向服务端传递字符串
package com.nio.socket;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws Exception {
char [] charArray = new char [3] ;
ServerSocket serverSocket = new ServerSocket(7777) ;
System.out.println(" accept begin "+ System.currentTimeMillis() ) ;
Socket socket = serverSocket . accept();
System.out.println("accept end " + System.currentTimeMillis()) ;
InputStream inputStream = socket.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
System. out. println ("read begin" + System.currentTimeMillis());
int readLength = inputStreamReader . read(charArray) ;
while (readLength != -1) {
String newString = new String(charArray, 0, readLength);
System.out.println(newString);
readLength = inputStreamReader.read(charArray);
System.out.println("read end " + System.currentTimeMillis());
inputStreamReader.close();
inputStream.close();
socket.close();
serverSocket.close();
}
}
}
package com.nio.socket;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws Exception {
System.out.println ("socket begin "+ System.currentTimeMillis()) ;
Socket socket = new Socket("localhost", 7777) ;
System.out.println( "socket end " + System.currentTimeMillis()); ;
Thread.sleep(3000);
OutputStream outputStream = socket .getOutputStream() ;
outputStream.write (" 我是外星人 " . getBytes()) ;
outputStream.close() ;
socket .close();
}
}
服务端向客户端传递字符串
package com.nio.socket.test41;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(7777) ;
System.out.println(" accept begin "+ System.currentTimeMillis() ) ;
Socket socket = serverSocket . accept();
System.out.println("accept end " + System.currentTimeMillis()) ;
OutputStream outputStream = socket.getOutputStream() ;
outputStream.write ( " 我来自 server 端 ! ".getBytes() );
outputStream.close();
socket .close();
serverSocket .close();
}
}
package com.nio.socket.test41;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws Exception {
System.out.println ("socket begin "+ System.currentTimeMillis()) ;
Socket socket = new Socket("localhost", 7777) ;
System.out.println( "socket end " + System.currentTimeMillis());
char [] charBuffer = new char [3];
InputStream inputStream = socket.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream) ;
System.out.println("serverB begin "+ System.currentTimeMillis()) ;
int readLength = inputStreamReader . read(charBuffer) ;
System.out.println("serverB begin " + System.currentTimeMillis());
while (readLength != 1) {
System.out.print(new String(charBuffer, 0, readLength));
readLength = inputStreamReader.read(charBuffer);
}
System.out.println(); ;
inputStream.close() ;
socket .close();
}
}
允许多次调用 write()方法进行写入操作
write()方法允许多次被调用 ,每执行一次就代表传递一次数据。
实现服务端与客户端多次的往来通信
package com.nio.socket.test5;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws Exception {
char [] charArray = new char [3] ;
ServerSocket serverSocket = new ServerSocket(7777) ;
System.out.println(" accept begin "+ System.currentTimeMillis() ) ;
Socket socket = serverSocket . accept();
System.out.println("accept end " + System.currentTimeMillis()) ;
//输入开始
InputStream inputStream = socket .getInputStream ( ) ;
ObjectInputStream objectInputStream = new ObjectInputStream (inputStream) ;
int byteLength = objectInputStream.readInt();
byte [] byteArray = new byte [byteLength] ;
objectInputStream . readFully(byteArray) ;
String newString = new String (byteArray);
System .out. println(newString );
//输入结束
//输出开始
OutputStream outputStream = socket .getOutputStream() ;
String strA = "客户端你好 A\n" ;
String strB = "客户端你好 B\n";
String strC = "客户端你好 C\n";
int allStrByteLength = (strA + strB + strC) .getBytes().length ;
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream) ;
objectOutputStream.write (allStrByteLength);
objectOutputStream.flush() ;
objectOutputStream.write(strA . getBytes());
objectOutputStream.write(strB.getBytes()) ;
objectOutputStream.write(strC .getBytes()) ;
objectOutputStream .flush() ;
//输出结束
//输入开始
byteLength = objectInputStream.readInt() ;
byteArray = new byte [byteLength] ;
objectInputStream .readFully(byteArray) ;
newString = new String(byteArray) ;
System.out.println(newString) ;
// 输入结束
//输出开始
strA ="客户端你好 D\n" ;
strB= "客户端你好E\n";
strC = " 客户端你好 F\n";
allStrByteLength = (strA + strB + strC) .getBytes() . length ;
objectOutputStream .writeInt (allStrByteLength);
objectOutputStream . flush () ;
objectOutputStream .write(strA .getBytes()) ;
objectOutputStream .write(strB .getBytes()) ;
objectOutputStream .write(strC .getBytes()) ;
objectOutputStream.flush() ;
//输出结束
inputStream . close () ;
socket.close();
serverSocket.close();
}
}
package com.nio.socket.test5;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws Exception {
System.out.println ("socket begin "+ System.currentTimeMillis()) ;
Socket socket = new Socket("localhost", 7777) ;
System.out.println( "socket end " + System.currentTimeMillis());
OutputStream outputStream = socket .getOutputStream();
InputStream inputStream = socket.getInputStream() ;
// 输出开始
ObjectOutputStream objectOutputStream = new ObjectOutputStream (outputStream) ;
String strA = "服务端你好A\n";
String strB = " 服务端你好 B\n";
String strC = "服务端你好 C\n";
int allStrByteLength = (strA + strB + strC) . getBytes() .length ;
objectOutputStream.write(allStrByteLength) ;
objectOutputStream.flush() ;
objectOutputStream .write(strA.getBytes()) ;
objectOutputStream.write(strB.getBytes()) ;
objectOutputStream .write(strC.getBytes()) ;
objectOutputStream.flush() ;
//输出结束
// 输入开始
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
int byteLength = objectInputStream.readInt() ;
byte [] byteArray = new byte [byteLength] ;
objectInputStream .readFully(byteArray);
String newString = new String(byteArray) ;
System .out.println(newString);
//输入结束
//输出开始
strA = "服务端你好D\n";
strB ="服务端你好 E\n";
strC = "服务端你好F\n";
allStrByteLength = (strA + strB + strC) .getBytes() . length ;
objectOutputStream .writeInt(allStrByteLength) ;
objectOutputStream.flush();
objectOutputStream .write(strA.getBytes()) ;
objectOutputStream .write(strB.getBytes()) ;
objectOutputStream.write(strC.getBytes()) ;
objectOutputStream.flush () ;
//输出结束
//输入开始
byteLength = objectInputStream.readInt();
byteArray = new byte[byteLength] ;
objectInputStream.readFully(byteArray) ;
newString = new String(byteArray) ;
System . out .println(newString) ;
//输入结束
objectOutputStream.close() ;
outputStream.close() ;
socket .close();
}
}
调用 Stream 的 close()方法造成 Socket 关闭
/**
* Closes the stream.
*/
private boolean closing = false;
public void close() throws IOException {
// Prevent recursion. See BugId 4484411
if (closing)
return;
closing = true;
if (socket != null) {
if (!socket.isClosed())
socket.close();
} else
impl.close();
closing = false;
}
使用Socket传递PNG图片文件