Java Socket基础

本文详细介绍Java Socket的基础通信原理,包括长连接与短连接的应用场景。通过示例代码讲解客户端和服务端如何实现消息交互,覆盖文本及对象数据传输,并提供常见异常处理方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java Socket基础
较基础的Java Socket通信样例!
一、长连接通信
客户端和服务端建立通道后,Socket一直开着。两端通过read()等待消息。
1)简易聊天
服务端可主动对各个客户端发送消息,而各客户端只能单独发送给服务端。当然,只要你愿意,在服务端改下,即可转发了。
附件解压工程ChatSocket,运行TestServer、TestClient即可。src下还有两批处理,详细看TestServer文件内注释了。
1.1)ChatServer.java

  1. /**
  2. *长连接、1对n主动发消息的服务器
  3. *
  4. *@authorJoin
  5. */
  6. publicclassChatServerextendsThread{
  7. /**服务端口*/
  8. privateintport;
  9. /**服务套接字*/
  10. privateServerSocketmServerSocket;
  11. /**线程池*/
  12. privateExecutorServicepool;
  13. /**客户端套接字集合*/
  14. privateArrayList<Socket>mClientList;
  15. publicChatServer(intport){
  16. this.port=port;
  17. pool=Executors.newCachedThreadPool();//缓存线程池
  18. mClientList=newArrayList<Socket>();
  19. }
  20. @Override
  21. publicvoidrun(){
  22. try{
  23. mServerSocket=newServerSocket(port);//创建本地特定端口服务器套接字
  24. Socketclient=null;
  25. while(true){
  26. client=mServerSocket.accept();//接收连接的套接字
  27. mClientList.add(client);//加入客户端列表
  28. System.out.println(client.getInetAddress()+"建立了连接");
  29. pool.execute(newThreadServer(client));//新线程执行任务
  30. }
  31. }catch(BindExceptione){//端口使用中
  32. System.out.println("端口使用中,请关闭后重开!");
  33. }catch(IOExceptione){
  34. e.printStackTrace();
  35. }
  36. }
  37. /**各个连接客户端的服务线程*/
  38. privateclassThreadServerextendsThread{
  39. privateSocketclient;
  40. publicThreadServer(Socketclient){
  41. this.client=client;
  42. }
  43. @Override
  44. publicvoidrun(){
  45. DataInputStreamin=null;
  46. DataOutputStreamout=null;
  47. try{
  48. in=newDataInputStream(client.getInputStream());
  49. out=newDataOutputStream(client.getOutputStream());
  50. BufferedReaderwt=newBufferedReader(newInputStreamReader(
  51. System.in));//控制台输入流
  52. while(true){
  53. if(in.available()>0){
  54. /*有数据时接收*/
  55. Stringstr=in.readUTF();
  56. System.out.println(str);
  57. /*接收end或空时,退出*/
  58. if(null==str||"end".equals(str)){
  59. System.out
  60. .println(client.getInetAddress()+"正常退出");
  61. break;
  62. }
  63. /*回复或转发已接收数据*/
  64. }else{
  65. if(wt.ready()){
  66. /*控制台有数据时发送*/
  67. Stringstr=wt.readLine();
  68. sendMessage(str);//群发消息
  69. }else{
  70. try{
  71. /*发送紧急数据,判断连接*/
  72. client.sendUrgentData(0xFF);
  73. Thread.sleep(100);
  74. }catch(Exceptione){
  75. System.out.println(client.getInetAddress()
  76. +"断开连接");
  77. break;
  78. }
  79. }
  80. }
  81. }
  82. }catch(SocketExceptione){//Connectionreset
  83. System.out.println(client.getInetAddress()+"异常退出");
  84. }catch(IOExceptione){
  85. e.printStackTrace();
  86. }finally{
  87. mClientList.remove(client);//移除当前客户端
  88. try{
  89. if(null!=in){
  90. in.close();
  91. }
  92. if(null!=out){
  93. out.close();
  94. }
  95. if(null!=client){
  96. client.close();
  97. }
  98. }catch(IOExceptione){
  99. e.printStackTrace();
  100. }
  101. }
  102. }
  103. }
  104. /**
  105. *群发信息
  106. *@throwsIOException
  107. */
  108. publicvoidsendMessage(Stringmsg)throwsIOException{
  109. DataOutputStreamout=null;
  110. for(Socketclient:mClientList){
  111. out=newDataOutputStream(client.getOutputStream());
  112. out.writeUTF(msg);
  113. out.flush();
  114. }
  115. }
  116. }
1.2)ChatClient.java

  1. /**
  2. *接收和发送消息的客户端
  3. *
  4. *@authorJoin
  5. */
  6. publicclassChatClientextendsThread{
  7. /**套接字地址*/
  8. privateSocketAddressaddress;
  9. /**超时时间*/
  10. privateinttimeout;
  11. publicChatClient(Stringhost,intport,inttimeout){
  12. this.address=newInetSocketAddress(host,port);
  13. this.timeout=timeout;
  14. }
  15. @Override
  16. publicvoidrun(){
  17. Socketsocket=newSocket();//创建未连接套接字
  18. try{
  19. //socket.setOOBInline(false);//默认即是false,表示不处理紧急数据
  20. socket.connect(address,timeout);//连接到服务器,并指定超时时间
  21. handleSocket(socket);//数据接收发送处理
  22. }catch(ConnectExceptione){//拒绝连接
  23. System.out.println("连接不上服务器");
  24. }catch(SocketTimeoutExceptione){//连接超时
  25. System.out.println("连接服务器超时");
  26. }catch(IOExceptione){
  27. e.printStackTrace();
  28. }finally{
  29. try{
  30. if(null!=socket){
  31. socket.close();//关闭Socket
  32. }
  33. }catch(IOExceptione){
  34. e.printStackTrace();
  35. }
  36. }
  37. }
  38. privatevoidhandleSocket(Socketsocket){
  39. DataInputStreamin=null;
  40. DataOutputStreamout=null;
  41. try{
  42. in=newDataInputStream(socket.getInputStream());
  43. out=newDataOutputStream(socket.getOutputStream());
  44. BufferedReaderwt=newBufferedReader(newInputStreamReader(
  45. System.in));//控制台输入流
  46. while(true){
  47. if(wt.ready()){
  48. /*控制台有数据时发送*/
  49. Stringstr=wt.readLine();
  50. out.writeUTF(str);
  51. out.flush();
  52. /*发送end时,自身也退出*/
  53. if(str.equals("end")){
  54. break;
  55. }
  56. }else{
  57. try{
  58. /*发送紧急数据,判断连接*/
  59. socket.sendUrgentData(0xFF);
  60. Thread.sleep(100);
  61. }catch(Exceptione){
  62. System.out.println("服务器断开连接");
  63. break;
  64. }
  65. }
  66. /*有数据时接收并输出*/
  67. if(in.available()>0)
  68. System.out.println(in.readUTF());
  69. }
  70. }catch(SocketExceptione){//Connectionreset
  71. System.out.println("服务器异常");
  72. }catch(IOExceptione){
  73. e.printStackTrace();
  74. }finally{
  75. try{
  76. if(null!=in){
  77. in.close();
  78. }
  79. if(null!=out){
  80. out.close();
  81. }
  82. }catch(IOExceptione){
  83. e.printStackTrace();
  84. }
  85. }
  86. }
  87. }

2)对象消息

发送对象消息。服务端有LinkServer和LinkServer2两个,分别支持单客户端与多客户端,方式也有些不一样。
附件解压工程LinkedSocketB,.test包内Test开头的即是测试类了。服务端接收到客户端连接时,直接一个循环发送n个对象过去,没什么大问题^^。
2.1)LinkClient.java

  1. /**
  2. *只建立一个Socket,长连接Server接收数据。
  3. *
  4. *@authorJoin
  5. */
  6. publicclassLinkClientextendsThread{
  7. /**套接字地址*/
  8. privateSocketAddressaddress;
  9. /**超时时间*/
  10. privateinttimeout;
  11. /**客户端监听接口*/
  12. privateOnLinkClientListenerlistener;
  13. /**
  14. *构造客户端
  15. *
  16. *@paramhost服务器名称
  17. *@paramport服务器端口
  18. *@paramtimeout连接超时时间
  19. */
  20. publicLinkClient(Stringhost,intport,inttimeout){
  21. this.address=newInetSocketAddress(host,port);
  22. this.timeout=timeout;
  23. }
  24. @Override
  25. publicvoidrun(){
  26. Socketsocket=newSocket();//创建未连接套接字
  27. try{
  28. socket.connect(address,timeout);//连接到服务器,并指定超时时间
  29. if(null!=listener){
  30. listener.onConnected();
  31. }
  32. receiveObj(socket);//接收服务器数据
  33. }catch(ConnectExceptione){//拒绝连接
  34. if(null!=listener){
  35. listener.onConnectException();
  36. }
  37. }catch(SocketTimeoutExceptione){//连接超时
  38. if(null!=listener){
  39. listener.onTimeoutException();
  40. }
  41. }catch(IOExceptione){
  42. e.printStackTrace();
  43. }finally{
  44. try{
  45. if(null!=socket){
  46. socket.close();//关闭Socket
  47. }
  48. }catch(IOExceptione){
  49. e.printStackTrace();
  50. }
  51. }
  52. }
  53. /**接收服务器发送的对象*/
  54. privatevoidreceiveObj(Socketsocket){
  55. //socket.shutdownOutput();//半关闭输出流
  56. ObjectInputStreamis=null;
  57. try{
  58. is=newObjectInputStream(newBufferedInputStream(
  59. socket.getInputStream()));
  60. /**循环接收对象*/
  61. while(true){
  62. Objectobj=is.readObject();
  63. if(null==obj){
  64. break;
  65. }
  66. if(null!=listener){
  67. listener.onReceive(obj);
  68. }
  69. }
  70. if(null!=listener){
  71. listener.onExited();
  72. }
  73. }catch(SocketExceptione){//Connectionreset
  74. if(null!=listener){
  75. listener.onSocketException();
  76. }
  77. }catch(IOExceptione){
  78. e.printStackTrace();
  79. }catch(ClassNotFoundExceptione){
  80. e.printStackTrace();
  81. }finally{
  82. try{
  83. if(null!=is){
  84. is.close();
  85. }
  86. if(null!=socket){
  87. socket.close();
  88. }
  89. }catch(IOExceptione){
  90. e.printStackTrace();
  91. }
  92. }
  93. }
  94. /**设置客户端监听接口*/
  95. publicvoidsetOnLinkClientListener(OnLinkClientListenerlistener){
  96. this.listener=listener;
  97. }
  98. }
2.2)LinkServer.java

  1. /**
  2. *开启服务器,长连接一个Socket,主动发送数据
  3. *
  4. *@authorJoin
  5. */
  6. publicclassLinkServerextendsThread{
  7. /**服务端口*/
  8. privateintport;
  9. /**服务套接字*/
  10. privateServerSocketmServerSocket;
  11. /**线程池*/
  12. privateExecutorServicepool;
  13. /**服务器监听接口*/
  14. privateOnLinkServerListenerlistener;
  15. /**同步对象*/
  16. privateObjectlockObj=newObject();
  17. /**是否等待*/
  18. privatebooleanisWaiting=false;
  19. /**发送对象集合*/
  20. privateArrayList<Object>sendObjList;
  21. publicLinkServer(intport){
  22. this.port=port;
  23. pool=Executors.newCachedThreadPool();//缓存线程池
  24. sendObjList=newArrayList<Object>();
  25. }
  26. @Override
  27. publicvoidrun(){
  28. try{
  29. mServerSocket=newServerSocket(port);//创建本地特定端口服务器套接字
  30. Socketclient=null;
  31. client=mServerSocket.accept();//接收连接的套接字
  32. if(null!=listener){
  33. listener.onClientConnected(client.getInetAddress());
  34. }
  35. pool.execute(newThreadServer(client));//新线程执行任务
  36. }catch(BindExceptione){//端口使用中
  37. if(null!=listener){
  38. listener.onBindException();
  39. }
  40. }catch(IOExceptione){
  41. e.printStackTrace();
  42. }
  43. }
  44. /**各个连接客户端的服务线程*/
  45. privateclassThreadServerextendsThread{
  46. privateSocketclient;
  47. publicThreadServer(Socketclient){
  48. this.client=client;
  49. }
  50. @Override
  51. publicvoidrun(){
  52. ObjectOutputStreamos=null;
  53. try{
  54. os=newObjectOutputStream(client.getOutputStream());
  55. ObjectsendObj;
  56. synchronized(lockObj){
  57. while(true){
  58. if(sendObjList.size()<=0){
  59. isWaiting=true;
  60. lockObj.wait();
  61. }
  62. sendObj=sendObjList.get(0);
  63. os.writeObject(sendObj);
  64. os.flush();
  65. /*发送null时,表示退出了*/
  66. if(null==sendObj){
  67. if(null!=listener){
  68. listener.onExited(client.getInetAddress());
  69. }
  70. break;
  71. }
  72. sendObjList.remove(0);
  73. }
  74. }
  75. }catch(SocketExceptione){//Connectionreset
  76. if(null!=listener){
  77. listener.onSocketException(client.getInetAddress());
  78. }
  79. }catch(IOExceptione){
  80. e.printStackTrace();
  81. }catch(InterruptedExceptione){
  82. e.printStackTrace();
  83. }finally{
  84. try{
  85. if(null!=os){
  86. os.close();
  87. }
  88. if(null!=client){
  89. client.close();
  90. }
  91. }catch(IOExceptione){
  92. e.printStackTrace();
  93. }
  94. }
  95. }
  96. }
  97. /**发送序列化对象*/
  98. publicvoidsendObj(Objectobj){
  99. /*这个判断非必需的,记得就好*/
  100. if(null!=obj&&!isSerializable(obj))
  101. thrownewIllegalArgumentException(
  102. "Objectneedstoimplementjava.io.Serializable!");
  103. sendObjList.add(obj);
  104. if(isWaiting){
  105. synchronized(lockObj){
  106. lockObj.notifyAll();
  107. }
  108. isWaiting=false;
  109. }
  110. }
  111. /**判断是否序列化*/
  112. privatebooleanisSerializable(Objectobj){
  113. Class<?>[]cls=obj.getClass().getInterfaces();
  114. for(Class<?>clazz:cls){
  115. if(clazz.getName().equals(Serializable.class.getName()))
  116. returntrue;
  117. }
  118. returnfalse;
  119. }
  120. /**设置服务器监听接口*/
  121. publicvoidsetOnLinkServerListener(OnLinkServerListenerlistener){
  122. this.listener=listener;
  123. }
  124. }
2.3)LinkServer2.java

 
  1. /**
  2. *开启服务器,长连接各个Socket,主动发送数据
  3. *
  4. *@authorJoin
  5. */
  6. publicclassLinkServer2extendsThread{
  7. /**服务端口*/
  8. privateintport;
  9. /**服务套接字*/
  10. privateServerSocketmServerSocket;
  11. /**服务器监听接口*/
  12. privateOnLinkServerListenerlistener;
  13. /**客户端套接字集合*/
  14. privateArrayList<Socket>clientList;
  15. /**客户端的输出流集合*/
  16. privateArrayList<ObjectOutputStream>osList;
  17. publicLinkServer2(intport){
  18. this.port=port;
  19. clientList=newArrayList<Socket>();
  20. osList=newArrayList<ObjectOutputStream>();
  21. }
  22. @Override
  23. publicvoidrun(){
  24. try{
  25. mServerSocket=newServerSocket(port);//创建本地特定端口服务器套接字
  26. Socketclient=null;
  27. while(true){
  28. client=mServerSocket.accept();//接收连接的套接字
  29. if(null!=listener){
  30. listener.onClientConnected(client.getInetAddress());
  31. }
  32. clientList.add(client);
  33. osList.add(newObjectOutputStream(client.getOutputStream()));//增加连接的输出流
  34. }
  35. }catch(BindExceptione){//端口使用中
  36. if(null!=listener){
  37. listener.onBindException();
  38. }
  39. }catch(IOExceptione){
  40. e.printStackTrace();
  41. }
  42. }
  43. /**发送序列化对象*/
  44. publicvoidsendObj(Objectobj){
  45. /*这个判断非必需的,记得就好*/
  46. if(null!=obj&&!isSerializable(obj))
  47. thrownewIllegalArgumentException(
  48. "Objectneedstoimplementjava.io.Serializable!");
  49. ObjectOutputStreamout=null;
  50. for(inti=0;i<osList.size();i++){
  51. try{
  52. out=osList.get(i);
  53. out.writeObject(obj);
  54. out.flush();
  55. /*发送null时,表示退出了*/
  56. if(null==obj){
  57. if(null!=listener){
  58. listener.onExited(clientList.get(i).getInetAddress());
  59. }
  60. closeSocket(i);//关闭当前Socket
  61. i--;//少了个记得减
  62. }
  63. }catch(SocketExceptione){//Connectionreset
  64. if(null!=listener){
  65. listener.onSocketException(clientList.get(i)
  66. .getInetAddress());
  67. }
  68. closeSocket(i);//关闭当前Socket
  69. i--;//少了个记得减
  70. }catch(IOExceptione){
  71. e.printStackTrace();
  72. closeSocket(i);//关闭当前Socket
  73. i--;//少了个记得减
  74. }
  75. }
  76. }
  77. /**关闭某个Socket*/
  78. privatevoidcloseSocket(intindex){
  79. try{
  80. osList.get(index).close();
  81. osList.remove(index);
  82. clientList.get(index).close();
  83. clientList.remove(index);
  84. }catch(IOExceptione1){
  85. e1.printStackTrace();
  86. }
  87. }
  88. /**判断是否序列化*/
  89. privatebooleanisSerializable(Objectobj){
  90. Class<?>[]cls=obj.getClass().getInterfaces();
  91. for(Class<?>clazz:cls){
  92. if(clazz.getName().equals(Serializable.class.getName()))
  93. returntrue;
  94. }
  95. returnfalse;
  96. }
  97. /**设置服务器监听接口*/
  98. publicvoidsetOnLinkServerListener(OnLinkServerListenerlistener){
  99. this.listener=listener;
  100. }
  101. }
二、短连接通信
客户端请求一次,建立一次Socket,完成后即可关闭。服务端通过accept()等待。
1)对象消息
客户端发送对象,服务端接受对象,很简单的例子。
1.1)EasyClient.java

  1. /**
  2. *每次连接服务器发送一个消息
  3. *
  4. *@authorJoin
  5. */
  6. publicclassEasyClient{
  7. /**套接字地址*/
  8. privateSocketAddressaddress;
  9. /**超时时间*/
  10. privateinttimeout;
  11. /**客户端监听接口*/
  12. privateOnClientListenerlistener;
  13. publicEasyClient(Stringhost,intport,inttimeout){
  14. this.address=newInetSocketAddress(host,port);
  15. this.timeout=timeout;
  16. }
  17. /**
  18. *发送一个消息
  19. *
  20. *@paramobj对象消息
  21. */
  22. publicbooleansendMessage(Objectobj){
  23. booleanresult=false;
  24. Socketsocket=null;
  25. try{
  26. socket=newSocket();
  27. socket.connect(address,timeout);
  28. if(null!=listener){
  29. listener.onConnected();
  30. }
  31. result=sendMessage(socket,obj);
  32. }catch(ConnectExceptione){//拒绝连接
  33. if(null!=listener){
  34. listener.onConnectException();
  35. }
  36. }catch(SocketTimeoutExceptione){//连接超时
  37. if(null!=listener){
  38. listener.onTimeoutException();
  39. }
  40. }catch(IOExceptione){
  41. e.printStackTrace();
  42. }finally{
  43. try{
  44. if(null!=socket){
  45. socket.close();//关闭Socket
  46. socket=null;
  47. }
  48. }catch(IOExceptione){
  49. e.printStackTrace();
  50. }
  51. }
  52. returnresult;
  53. }
  54. /**通过Socket发送obj消息*/
  55. privatebooleansendMessage(Socketsocket,Objectobj){
  56. booleanresult=false;
  57. ObjectOutputStreamos=null;
  58. try{
  59. os=newObjectOutputStream(socket.getOutputStream());
  60. os.writeObject(obj);
  61. os.flush();
  62. if(null!=listener){
  63. listener.onMessageSent(obj);
  64. }
  65. result=true;
  66. }catch(SocketExceptione){//Connectionreset
  67. if(null!=listener){
  68. listener.onSocketException();
  69. }
  70. }catch(IOExceptione){
  71. e.printStackTrace();
  72. }finally{
  73. try{
  74. if(null!=os){
  75. os.close();
  76. }
  77. }catch(IOExceptione){
  78. e.printStackTrace();
  79. }
  80. }
  81. returnresult;
  82. }
  83. /**设置客户端监听接口*/
  84. publicvoidsetOnClientListener(OnClientListenerlistener){
  85. this.listener=listener;
  86. }
  87. }
1.2)EasyServer.java

  1. publicclassEasyServerextendsThread{
  2. /**服务端口*/
  3. privateintport;
  4. /**服务套接字*/
  5. privateServerSocketmServerSocket;
  6. /**服务器监听接口*/
  7. privateOnServerListenerlistener;
  8. publicEasyServer(intport){
  9. this.port=port;
  10. }
  11. @Override
  12. publicvoidrun(){
  13. try{
  14. mServerSocket=newServerSocket(port);//创建本地特定端口服务器套接字
  15. Socketsocket=null;
  16. while(true){
  17. socket=mServerSocket.accept();//接收连接的套接字
  18. receiveMessage(socket);//接收socket处理消息
  19. }
  20. }catch(BindExceptione){//端口使用中
  21. if(null!=listener){
  22. listener.onBindException();
  23. }
  24. }catch(IOExceptione){
  25. e.printStackTrace();
  26. }
  27. }
  28. /**接收处理每个Socket信息*/
  29. privatevoidreceiveMessage(Socketsocket){
  30. ObjectInputStreamis=null;
  31. try{
  32. is=newObjectInputStream(newBufferedInputStream(
  33. socket.getInputStream()));
  34. Objectobj=is.readObject();
  35. if(null!=listener){
  36. listener.onReceive(socket.getInetAddress(),obj);
  37. }
  38. }catch(SocketExceptione){//Connectionreset
  39. if(null!=listener){
  40. listener.onSocketException(socket.getInetAddress());
  41. }
  42. }catch(IOExceptione){
  43. e.printStackTrace();
  44. }catch(ClassNotFoundExceptione){
  45. e.printStackTrace();
  46. }finally{
  47. try{
  48. if(null!=is){
  49. is.close();
  50. }
  51. if(null!=socket){
  52. socket.close();
  53. }
  54. }catch(IOExceptione){
  55. e.printStackTrace();
  56. }
  57. }
  58. }
  59. /**设置服务器监听接口*/
  60. publicvoidsetOnServerListener(OnServerListenerlistener){
  61. this.listener=listener;
  62. }
  63. }
三、后记
恩,哦,socket还有个比较常用的是setSoTimeout(),在read()阻塞超时会报SocketTimeoutException,catch住处理即可。
更多的如SSLSocket、NIO的简单例子,可以先 Click here!这个整理好的样例工程就不提供了,自己动手^^!

ps:老遇到8W冗余字符,拆着拆着就三个了==!

出处http://vaero.blog.51cto.com/4350852/893847

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值