Socket和ServerSocket学习笔记

转自 http://www.cnblogs.com/rond/p/3565113.html

对于即时类应用或者即时类的游戏,HTTP协议很多时候无法满足于我们的需求。这会,Socket对于我们来说就非常实用了。下面是本次学习的笔记。主要分异常类型、交互原理、Socket、ServerSocket、多线程这几个方面阐述。

 

异常类型
在了解Socket的内容之前,先要了解一下涉及到的一些异常类型。以下四种类型都是继承于IOException,所以很多之后直接弹出IOException即可。
UnkownHostException:      主机名字或IP错误
ConnectException:        服务器拒绝连接、服务器没有启动、(超出队列数,拒绝连接)
SocketTimeoutException:      连接超时
BindException:          Socket对象无法与制定的本地IP地址或端口绑定
 
交互过程
Socket与ServerSocket的交互,下面的图片我觉得已经说的很详细很清楚了。
 
Socket
构造函数

Socket()

Socket(InetAddress address, int port)throws UnknownHostException, IOException
Socket(InetAddress address, int port, InetAddress localAddress, int localPort)throws IOException
Socket(String host, int port)throws UnknownHostException, IOException
Socket(String host, int port, InetAddress localAddress, int localPort)throws IOException
 
除去第一种不带参数的之外,其它构造函数会尝试建立与服务器的连接。如果失败会抛出IOException错误。如果成功,则返回Socket对象。
InetAddress是一个用于记录主机的类,其静态getHostByName(String msg)可以返回一个实例,其静态方法getLocalHost()也可以获得当前主机的IP地址,并返回一个实例。Socket(String host, int port, InetAddress localAddress, int localPort)构造函数的参数分别为目标IP、目标端口、绑定本地IP、绑定本地端口。
 
Socket方法
getInetAddress();      远程服务端的IP地址
getPort();          远程服务端的端口
getLocalAddress()      本地客户端的IP地址
getLocalPort()        本地客户端的端口
getInputStream();     获得输入流
getOutStream();      获得输出流
值得注意的是,在这些方法里面,最重要的就是getInputStream()和getOutputStream()了。
 
Socket状态
isClosed();            //连接是否已关闭,若关闭,返回true;否则返回false
isConnect();      //如果曾经连接过,返回true;否则返回false
isBound();            //如果Socket已经与本地一个端口绑定,返回true;否则返回false
如果要确认Socket的状态是否处于连接中,下面语句是很好的判断方式。
boolean isConnection=socket.isConnected() && !socket.isClosed();   //判断当前是否处于连接

 

半关闭Socket
很多时候,我们并不知道在获得的输入流里面到底读多长才结束。下面是一些比较普遍的方法:
  • 自定义标识符(譬如下面的例子,当受到“bye”字符串的时候,关闭Socket)
  • 告知读取长度(有些自定义协议的,固定前几个字节表示读取的长度的)
  • 读完所有数据
  • 当Socket调用close的时候关闭的时候,关闭其输入输出流
 
ServerSocket
构造函数
ServerSocket()throws IOException
ServerSocket(int port)throws IOException
ServerSocket(int port, int backlog)throws IOException
ServerSocket(int port, int backlog, InetAddress bindAddr)throws IOException
 
注意点:
1. port服务端要监听的端口;backlog客户端连接请求的队列长度;bindAddr服务端绑定IP
2. 如果端口被占用或者没有权限使用某些端口会抛出BindException错误。譬如1~1023的端口需要管理员才拥有权限绑定。
3. 如果设置端口为0,则系统会自动为其分配一个端口;
4. bindAddr用于绑定服务器IP,为什么会有这样的设置呢,譬如有些机器有多个网卡。
5. ServerSocket一旦绑定了监听端口,就无法更改。ServerSocket()可以实现在绑定端口前设置其他的参数。
 
单线程的ServerSocket例子
复制代码
public void service(){
    while(true){
        Socket socket=null;
        try{
            socket=serverSocket.accept();//从连接队列中取出一个连接,如果没有则等待
            System.out.println("新增连接:"+socket.getInetAddress()+":"+socket.getPort());
            ...//接收和发送数据
        }catch(IOException e){e.printStackTrace();}finally{
            try{
                if(socket!=null) socket.close();//与一个客户端通信结束后,要关闭Socket
            }catch(IOException e){e.printStackTrace();}
        }
    }
}
复制代码

 

多线程的ServerSocket
多线程的好处不用多说,而且大多数的场景都是多线程的,无论是我们的即时类游戏还是IM,多线程的需求都是必须的。下面说说实现方式:
  • 主线程会循环执行ServerSocket.accept();
  • 当拿到客户端连接请求的时候,就会将Socket对象传递给多线程,让多线程去执行具体的操作;
实现多线程的方法要么继承Thread类,要么实现Runnable接口。当然也可以使用线程池,但实现的本质都是差不多的。
 
这里举例:
下面代码为服务器的主线程。为每个客户分配一个工作线程:
复制代码
public void service(){
    while(true){
        Socket socket=null;
        try{
            socket=serverSocket.accept();                        //主线程获取客户端连接
            Thread workThread=new Thread(new Handler(socket));    //创建线程
            workThread.start();                                    //启动线程
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}
复制代码

 

当然这里的重点在于如何实现Handler这个类。Handler需要实现Runnable接口:
复制代码
class Handler implements Runnable{
    private Socket socket;
    public Handler(Socket socket){
        this.socket=socket;
    }
    
    public void run(){
        try{
            System.out.println("新连接:"+socket.getInetAddress()+":"+socket.getPort());
            Thread.sleep(10000);
        }catch(Exception e){e.printStackTrace();}finally{
            try{
                System.out.println("关闭连接:"+socket.getInetAddress()+":"+socket.getPort());
                if(socket!=null)socket.close();
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }
}
复制代码

当然是先多线程还有其它的方式,譬如线程池,或者JVM自带的线程池都可以。这里就不说明了。

展开阅读全文

简单的SocketServerSocket的问题

05-05

import java.net.*;rnimport java.io.*;rnpublic class TalkClientrnrnrn public static void main(String args[])rn rn Socket client = null;rn tryrn rn client = new Socket("127.0.0.1",8888);rn rn catch (IOException e)rn rn System.out.println("连接不成功!"+e);rn rn tryrn rn DataInputStream inline = new DataInputStream(System.in);rn DataOutputStream out = new DataOutputStream(client.getOutputStream());rn DataInputStream in = new DataInputStream(client.getInputStream());rn String s = null ;rn s = inline.readUTF();rn rn while (!(s.equals("bye")))rn rn System.out.println(s);rn out.writeUTF(s);rn System.out.println("服务器说:"+in.readUTF());rn s = inline.readUTF();rn rn inline.close();rn out.close();rn in.close();rn client.close();rn rn rn catch (IOException e)rn rn System.out.println(e);rn rn rn rn rnrnimport java.net.*;rnimport java.io.*;rnrnpublic class TalkServerrnrn public static void main(String[] args)rn rn ServerSocket server = null ;rn tryrn rn server = new ServerSocket(8888);rn rn catch (IOException e)rn rn System.out.println("不能监听:"+e);rn System.exit(-1);rn rn Socket client = null;rn tryrn rn client = server.accept();rn System.out.println("客户端连接了!");rn rn catch (IOException e)rn rn System.out.println("客户端断开连接!"+e);rn System.exit(-1);rn rn tryrn rn DataInputStream in = new DataInputStream(client.getInputStream());rn DataOutputStream out = new DataOutputStream(client.getOutputStream());rn String line = null;rn DataInputStream inline = new DataInputStream(System.in);rn System.out.println("客户端说:"+in.readUTF());rn line = inline.readUTF();rn while (!(line.equals("bye")))rn rn out.writeUTF(line);rn out.flush();rn rn line = inline.readUTF();rn rn rn in.close();rn out.close();rn inline.close();rn client.close();rn rn rn catch (IOException e)rn rn System.out.println(e);rn rnrn rn rnrnrn服务器开启了,客服端连接上了,但客户端发不了信息出去,是不是我用的流不正确啊?请高手帮我看看,谢谢rn 论坛

ServerSocketSocket的问题

07-25

先看代码rn[color=#FF0000]《MultiJabberServer》[/color]rnrnimport java.io.*;rnimport java.net.*;rnrnpublic class MultiJabberServerrnrnrn static final int PORT = 8080;rnrn public static void main(String[] args)rn throws IOExceptionrn rn ServerSocket s = new ServerSocket(PORT);rn System.out.println("==服务端开始==");rn tryrn rn while (true)rn rn Socket socket = s.accept();rn tryrn rn new ServeOneJabber(socket);rn rn catch (IOException e)rn rn socket.close();rn rn rn rn finallyrn rn s.close();rn rn rn rnrnrn[color=#FF0000]《ServeOneJabber》[/color]rnimport java.io.*;rnimport java.net.*;rnrnpublic class ServeOneJabber extends Threadrnrnrn private Socket socket;rn private BufferedReader in;rn private PrintWriter out;rnrn public ServeOneJabber(Socket s)rn throws IOExceptionrn rn socket = s;rn in =rn new BufferedReader(rn new InputStreamReader(rn socket.getInputStream()));rn out =rn new PrintWriter(rn new BufferedWriter(rn new OutputStreamWriter(rn socket.getOutputStream())), true);rn start();rn rnrn @Overridern public void run()rn rn tryrn rn while (true)rn rn String str = in.readLine();rn if (str.equals("END"))rn rn break;rn rn System.out.println("==输出==" + str);rn out.println(str);rn rn System.out.println("==客户端退出了==");rn rn catch (IOException e)rn rn rn finallyrn rn tryrn rn socket.close();rn rn catch (IOException e)rn rn System.out.println("==客户端意外掉线了==");rn rn rn rnrnrn本人学生rn有个问题是:rn现在假设有两个客户端连接进来了 分别是A和Brn现在A传了个值给服务器rn我怎么做才能把这个值传给B?rn小弟不懂 new ServeOneJabber(socket)后rn直接交给线程start()了rn我怎么区分A和B? 论坛

socketserversocket 交互的问题

01-11

刚接触socket,想写一个简单的服务器和客户端通信的例子。过程是这样,一个main实例化一个serversocket,等待socket连接,每连接一个socket就创建一个ThreadServer线程处理,socket和ThreadServer都需要发送和接收消息。问题是发送和接收消息这里,我用的死循环,但是一定会阻塞,我不知道怎么处理,我想要的效果是,socket可以发送消息给ThreadServer,同时可以接收ThreadServer发送的消息,ThreadServer也可以发送消息给socket,也可以接收其消息!望不吝赐教!代码如下:rn[b]这是server端的代码,多线程类,main方法中实例一个serversocket。[/b]rn[code=java]package server;rnrnimport java.io.BufferedReader;rnimport java.io.IOException;rnimport java.io.InputStreamReader;rnimport java.io.PrintWriter;rnimport java.net.ServerSocket;rnimport java.net.Socket;rnrnpublic class ThreadServer extends Threadrn private static int port=10240;//端口号rn private Socket socket=null;//本线程处理的客户端socket的引用rn public ThreadServer(Socket socket)rn this.socket=socket;rn rn @Overridern public void run()rn tryrn String ret=null;rn dorn BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream()));//获得输入流rn PrintWriter out=new PrintWriter(socket.getOutputStream());//获得输出流rn BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));//键盘输入rn if(in.ready())//输入流可用rn ret=in.readLine();rn System.out.println("客户端说:"+ret);//打印输入流的内容rn in.close();rn System.out.print("请输入要发送给客户端的消息:");rn out.write(sin.readLine());//写入输出流rn out.close();rn sin.close();rn rn rn while("quit".equals(ret));//quit表示退出rn catch(IOException e)rn e.printStackTrace();rn rn rn public static void main(String[] args)rn try(ServerSocket server=new ServerSocket(port);) //服务器socketrn while(true)//循环侦听rn Socket socket=server.accept();rn new ThreadServer(socket).start();//启动新的处理线程rn rn catch (IOException e) rn e.printStackTrace();rn rn rnrn[/code]rn[b]这是客户端类[/b]rn[code=java]package client;rnrnimport java.io.BufferedReader;rnimport java.io.InputStreamReader;rnimport java.io.PrintWriter;rnimport java.net.Socket;rnrnpublic class Client extends Threadrn private static String serverIP="localhost";//服务器地址rn private static int port=10240;rn private Socket socket=null;rn public Client()rn tryrn socket=new Socket(serverIP,port);//实例化客户端socketrn catch(Exception e)rn e.printStackTrace();rn rn rn @Overridern public void run()rn tryrn String ret=null;rn dorn BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream()));rn PrintWriter out=new PrintWriter(socket.getOutputStream());rn BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));//获得流rn System.out.print("请输入要发送给服务器的消息:");rn out.write(sin.readLine());//写入输出流rn out.close();rn sin.close();rn if(in.ready())//输入流可用rn ret=in.readLine();rn System.out.println("服务器说:"+ret);rn in.close();rn rn while("quit".equals(ret));//退出rn catch(Exception e)rn e.printStackTrace();rn rn rn public static void main(String[] args)rn new Client().start();rn rnrn[/code] 论坛

SocketServerSocket之间的mp3文件传输

08-28

Socket端:rnimport java.io.BufferedInputStream;rnimport java.io.BufferedOutputStream;rnimport java.io.FileOutputStream;rnimport java.io.IOException;rnimport java.io.PrintWriter;rnimport java.net.Socket;rnimport java.net.UnknownHostException;rnrnpublic class Socketdemo rn public static void main(String[] args) rn Socket sk = null;rn try rn sk = new Socket("127.0.0.1", 8088);rn PrintWriter output = new PrintWriter(sk.getOutputStream());rn BufferedInputStream input = new BufferedInputStream(skrn .getInputStream());rn output.println("are you the one.mp3");rn output.flush();rn BufferedOutputStream bos = new BufferedOutputStream(rn new FileOutputStream("f:/copysong.mp3"));rn byte[] bb = new byte[5120];rn int b;rn while ((b = input.read(bb)) > 0) rn bos.write(bb, 0, b);rn bos.flush();rn rn bos.close();rn input.close();rn output.close();rn catch (UnknownHostException e) rn e.printStackTrace();rn catch (IOException e) rn e.printStackTrace();rn rnrn rnrnServerSocket端:rnimport java.io.BufferedInputStream;rnimport java.io.BufferedReader;rnimport java.io.FileInputStream;rnimport java.io.IOException;rnimport java.io.InputStreamReader;rnimport java.io.PrintWriter;rnimport java.net.ServerSocket;rnimport java.net.Socket;rnrnpublic class Serversocketdemo rn public static void main(String[] args) rn System.out.println("服务器启动....");rn ServerSocket ssk = null;rn try rn ssk = new ServerSocket(8088);rn while (true) rn Socket sk = ssk.accept();rn PrintWriter output = new PrintWriter(sk.getOutputStream());rn BufferedReader input = new BufferedReader(rn new InputStreamReader(sk.getInputStream()));rn String str = input.readLine();rn System.out.println(str);rn BufferedInputStream bis = new BufferedInputStream(rn new FileInputStream("e:/" + str));rn byte[] buf = new byte[5120];rn int a;rn while ((a = bis.read(buf)) > 0) rn String send = new String(buf);rn output.println(send);rn output.flush();rn rnrn bis.close();rn input.close();rn output.close();rn System.out.println("e:/" + str);rn rn catch (IOException e) rn e.printStackTrace();rn rn rnrnrn====================================================rn传输老是出错,本人刚刚入门学习,望各位大侠多多指教,谢谢了 论坛

没有更多推荐了,返回首页