二、传统Socket____________________________________________________________
需要实践TCP三次握手,四次分手,实践,不是只看理论!!!!!!!!!!!!!!!
1、socket与socketStream的关闭顺序,ServerScoket优雅关闭。
socket.close()注释这么说:Closing this socket will also close the socket's InputStream and OutputStream.但是,debug观察到的结果不是。
反而是关闭留后,会关闭socket,
2、最简单的socket,server只同时支持一个client的读写,尽管第二个client可以连接上可以write(server端阻塞在accept上),但是client会阻塞在getInputstream().read(),且不能优雅关闭,
server
/**
* @author timeriver.wang
* @date 2012-12-08 9:28:40 PM
*/
public class Server {
public static void main(String[] args){
ServerSocket ss;
try {
ss = new ServerSocket(8899);
while (true) {
Socket socket = ss.accept();
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
BufferedReader netInput = new BufferedReader( new InputStreamReader( is ) );
String receive = netInput.readLine();
while(receive != null){
System.out.println(receive);
os.write(("server echo: " + receive+"\r\n").getBytes("UTF-8"));
os.flush();
if("bye".equals(receive)){
break;
}
receive = netInput.readLine();
}
//用于测试关闭顺序,配合client的,比如去掉这句。
os.close();
socket.close();
System.out.println(socket);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
client
升级:增加一个buffer队列,从键盘读数据是一个线程,如果buffer不满就写,否则阻塞,向socket发送数据是一个线程,如果buffer不空就读,否则阻塞。从socket读数据再设一个线程,直接输出。
/**
* @author timeriver.wang
* @date 2012-12-08 9:28:40 PM
*/
public class Client {
public static void main( String[] args ){
try {
Socket so = new Socket( "127.0.0.1", 8899 );
System.out.println(so);
OutputStream os = so.getOutputStream();
InputStream is = so.getInputStream();
BufferedReader netInput = new BufferedReader( new InputStreamReader( is,"UTF-8" ) );
BufferedReader keyInput = new BufferedReader( new InputStreamReader( System.in,"UTF-8" ) );
String keyLine = null;
while((keyLine = keyInput.readLine())!=null){
System.out.println( "client say: " + keyLine );
os.write( (keyLine+"\r\n").getBytes("UTF-8") );
// write把数据发送给TCP层(操作系统网卡)缓存,一个TCP包20-40字节,为wirte每个byte单独发一个TCP包太奢侈,但可以flush
os.flush();
System.out.println(netInput.readLine());
if ( keyLine.equals( "bye" ) ) {
break;
}
}
os.close();
// 需要研究,主动关闭被动关闭FIN,RST, //用于测试关闭顺序,配合服务器的,比如去掉这句。
// so.close();
System.out.println( os );
}
catch ( Exception e ) {
e.printStackTrace();
}
}
}
3、多线程的serversocket, 可以支持多个client同时通信
/**
* @author timeriver.wang
* @date 2013-01-03 12:29:50 PM
*/
public class EchoServer {
public static void main( String args[] )throws IOException {
//更好的是这种方式new EchoServer().service();serverSocket,port通过构造函数初始化
ServerSocket serverSocket = new ServerSocket( 8899 );
while ( true ) {
Socket socket = serverSocket.accept();
Thread workThread = new Thread( new Handler( socket ) );
workThread.start();
}
}
}
class Handler implements Runnable {
//多线程只能通过构造传参,因为它的run方法是无参的,且只能通过run/start方法来启动一个新线程
private Socket socket;
public Handler( Socket socket ) {
this.socket = socket;
}
public void run() {
try {
/**
* 显示多个不同的socket连接,下面是console输出,2+main=3个线程,server端只需要一个port##
* New connection accepted: Socket[addr=/127.0.0.1,port=57098,localport=8899]
* client1-1
* New connection accepted: Socket[addr=/127.0.0.1,port=57102,localport=8899]
* client2-1
* client1-2
*/
System.out.println( "New connection accepted: " + socket);
BufferedReader br = new BufferedReader( new InputStreamReader( socket.getInputStream() ) );
PrintWriter pw = new PrintWriter( socket.getOutputStream(), true );
String msg = null;
while ( ( msg = br.readLine() ) != null ) {
System.out.println( msg );
pw.println( "echo:" + msg );
if ( msg.equals( "bye" ) )
break;
}
}catch ( IOException e ) {
e.printStackTrace();
}
finally {
try {
if ( socket != null )
socket.close();
}
catch ( IOException e ) {
e.printStackTrace();
}
}
}
}
4,固定数量的连接,使用Executors
public EchoServer() throws IOException {
serverSocket = new ServerSocket(port);
executorService = Executors.newFixedThreadPool(Runtime.getRuntime()
.availableProcessors() * POOL_SIZE);
}
public void service() {
while (true) {
Socket socket = null;
try {
socket = serverSocket.accept();
//不同之处
executorService.execute(new Handler(socket));
} catch (IOException e) {
e.printStackTrace();
}
}
}
5、主动关闭socket
while (!isShutdown) {
private boolean isShutdown=false;
改变isShutdown,public方法,或者通过socket thread。
半关闭
shutdownInput():关闭输入流。
shutdownOutput(): 关闭输出流。
不会释放Socket占用的资 源,比如占用的本地端口等
比如QQ传送大文件一半时,取消发送,暂停,断点续传?