3、Socket编程

1、服务器端获取客服端传来的数据:

直接在eclipse中新建一个Server类:

import java.io.*;
import java.net.*;
public class Server {  
public static void main(String args[]) throws IOException {    
      int port = 8899;  
      //定义一个ServerSocket监听在端口8899上  
      ServerSocket server = new ServerSocket(port);  
      //server尝试接收客户端Socket的连接请求,server的accept方法是阻塞式的  
      Socket socket = server.accept();  
      //读取客户端发过来的信息  
      Reader reader = new InputStreamReader(socket.getInputStream());  
      char chars[] = new char[64];  
      int len;  
      StringBuilder sb = new StringBuilder();  
      while ((len=reader.read(chars)) != -1) {  
         sb.append(new String(chars, 0, len));  
      }  
      System.out.println("from client: " + sb);  
      reader.close();  
      socket.close();  
      server.close();  
   }  
}


阻塞式:当服务器socket接收到数据才往后执行,没有收到数据就暂停在当前程序位置等待数据。

可以先执行Server的主方法,执行后,查看端口:cmd-->netstat -ano 就会发现8899端口处于监听的状态。

根据进程pid查看该端口被那个应用占用:

C:\Users\Administrator>tasklist|findstr 4844
javaw.exe                     4844 Console                    1     14,992 K

说明Server类的主方法并没有执行完毕。


Client类:

import java.io.*;
import java.net.*;
public class Client{
	public static void main(String args[]) throws Exception {  
	      String host = "127.0.0.1";  //要连接的服务端IP地址  
	      int port = 8899;   //要连接的服务端对应的监听端口  
	      //与服务端建立连接  
	      Socket client = new Socket(host, port);  
	      //建立连接后就可以往服务端写数据了  
	      Writer writer = new OutputStreamWriter(client.getOutputStream());  
	      writer.write("Hello Server.");  
	      writer.flush();//写完后要记得flush  
	      writer.close();  
	      client.close();  
	   }  
}
执行Client的主方法,控制台上打印:from client: Hello Server.

这时再去查看端口8899,发现端口已经被关闭,Server的主方法执行完毕。

若先执行Client主方法会是怎样?会出现Connection refused: connect

若将Client类中writer.flush();删掉会是怎样?此时还是能读取到from client: Hello Server.


2、客服端、服务器同时读写数据

每次数据写入时 添加结束标记:"eof";发现端口8899开启过多可以先关闭eclipse或javaw.exe,确保每次运行Server之前8899端口是关闭的。

Server:

import java.io.*;
import java.net.*;
public class Server {  
	public static void main(String args[]) throws IOException {  
	      int port = 8899;  
	      ServerSocket server = new ServerSocket(port);  
	      Socket socket = server.accept();  
	      Reader reader = new InputStreamReader(socket.getInputStream());  
	      char chars[] = new char[64];  
	      int len;  
	      StringBuilder sb = new StringBuilder();  
	      String temp;  
	      int index;  
	      while ((len=reader.read(chars)) != -1) {  
	         temp = new String(chars, 0, len);  
	         if ((index = temp.indexOf("eof")) != -1) {//遇到eof时就结束接收  
	            sb.append(temp.substring(0, index));  
	            break;  
	         }  
	         sb.append(temp);  
	      }  
	      System.out.println("from client: " + sb);  
	      //读完后写一句  
	      Writer writer = new OutputStreamWriter(socket.getOutputStream());  
	      writer.write("Hello Client32.eof3232");   //出现eof表示输入结束
	      writer.flush();  
	      writer.close();  
	      reader.close();  
	      socket.close();  
	      server.close();  
	   }  
}
Client类:

import java.io.*;
import java.net.*;
public class Client{
	 public static void main(String args[]) throws Exception {  
	     String host = "127.0.0.1";  //要连接的服务端IP地址  
	     int port = 8899;   //要连接的服务端对应的监听端口  
	     Socket client = new Socket(host, port);  
	     Writer writer = new OutputStreamWriter(client.getOutputStream());  
	      writer.write("Hello Server");  
	      writer.write("eof");  
	      writer.flush();  
	      Reader reader = new InputStreamReader(client.getInputStream());  
	      char chars[] = new char[64];  
	      int len;  
	      StringBuffer sb = new StringBuffer();  
	      String temp;  
	      int index;  
	      while ((len=reader.read(chars)) != -1) {  
	         temp = new String(chars, 0, len);  
	         if ((index = temp.indexOf("eof")) != -1) {  
	            sb.append(temp.substring(0, index));  
	            break;  
	         }  
	         sb.append(new String(chars, 0, len));  
	      }  
	      System.out.println("from server: " + sb);  
	      reader.close();  
	      writer.close();  
	      client.close();  
	   }  
}
还是先执行Server主方法再执行Client主方法:

点击Console按钮切换Server/Client的打印信息:

from server: Hello Client32.

from client: Hello Server


3、多个客户端链接同一个服务器端

这才是实际需要的,还是以"eof"为结束标记;这里没有关闭端口。

Server:每次ServerSocket接收到一个新的Socket连接请求后新建一个线程来跟当前Socket进行通信,实现并发处理与客户端Socket进行通信的情况。由于现在的Server是异步处理数据的,不必一次性将客户端传来的数据读完,可以使用BufferedReader这个类,每次读取一行数据。

import java.io.*;
import java.net.*;
public class Server {  
@SuppressWarnings("resource")
public static void main(String args[]) throws IOException {  
     int port = 8899;  
     ServerSocket server = new ServerSocket(port);  
      while (true) {  
         Socket socket = server.accept();  
         new Thread(new Task(socket)).start();   //启动Runnable接口下类的run()方法;
      }  
   }  
     
   /** 
    * 用来处理Socket请求的 
   */  
   static class Task implements Runnable {  
   
      private Socket socket;  
        
      public Task(Socket socket) {  
         this.socket = socket;  
      }  
        
      public void run() {  
         try {  
            handleSocket();  
         } catch (Exception e) {  
            e.printStackTrace();  
         }  
      }  
        
      /** 
       * 跟客户端Socket进行通信 
      * @throws Exception 
       */  
      private void handleSocket() throws Exception {  
         BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));  
         StringBuilder sb = new StringBuilder();  
         String temp;  
         int index;  
         while ((temp=br.readLine()) != null) {  
            if ((index = temp.indexOf("eof")) != -1) {//遇到eof时就结束接收  
             sb.append(temp.substring(0, index));  
                break;  
            }  
            sb.append(temp);  
         }  
         System.out.println("from client: " + sb);  
         //读完后写一句  
       Writer writer = new OutputStreamWriter(socket.getOutputStream());  
         writer.write("Hello Client.");  
         writer.write("eof");  
         writer.flush();  
         writer.close();  
         br.close();  
         socket.close();  
      }  
   }  
}  


可以用线程实例多个Client对象模拟并发访问Server,这里就不实现了(也可以创建2个Client类简单模拟下)。

import java.io.*;
import java.net.*;
public class Client{
	public static void main(String args[]) throws Exception {  
	     String host = "127.0.0.1";  //要连接的服务端IP地址  
	     int port = 8899;   //要连接的服务端对应的监听端口  
	     Socket client = new Socket(host, port);  
	     Writer writer = new OutputStreamWriter(client.getOutputStream());  
	      writer.write("Hello Server first\n");  
	      writer.write("Hello Server second\n");  
	      writer.write("eof\n");  
	      writer.flush();  
	     BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));  
	      StringBuffer sb = new StringBuffer();  
	      String temp;  
	      int index;  
	      while ((temp=br.readLine()) != null) {  
	         if ((index = temp.indexOf("eof")) >0) {  
	            sb.append(temp.substring(0, index));  
	            break;  
	         }  
	         sb.append(temp);  
	      }  
	      System.out.println("from server: " + sb);  
	      writer.close();  
	      br.close();  
	      client.close();  
	   }  
}
设置编码:BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));  

         Writer writer = new OutputStreamWriter(socket.getOutputStream(), "UTF-8"); 

设置阻塞超时中断连接(一般设置在客户端),Socket提供setSoTimeout()方法来设置接收数据的超时时间,单位是毫秒,抛出SocketTimeoutException

在server中添加:

        Thread.sleep(5000);
       //  writer.flush();  

Client:

import java.io.*;
import java.net.*;
public class Client{
	public static void main(String args[]) throws Exception {  
	     String host = "127.0.0.1";  //要连接的服务端IP地址  
	     int port = 8899;   //要连接的服务端对应的监听端口  
	     Socket client = new Socket(host, port);  
	     Writer writer = new OutputStreamWriter(client.getOutputStream());  
	      writer.write("Hello Server 我的\n");  
	      writer.write("Hello Server second\n");  
	      writer.write("eof\n");  
	      writer.flush();  
	     BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));  
	      client.setSoTimeout(2000);  
	      StringBuffer sb = new StringBuffer();  
	      try{
	    	  String temp;  
	    	  int index;  
	    	  while ((temp=br.readLine()) != null) {  
	    		  if ((index = temp.indexOf("eof")) >0) {  
	    			  sb.append(temp.substring(0, index));  
	    			  break;  
	    		  }  
	    		  sb.append(temp);  
	    	  }  
	      }catch(SocketTimeoutException e){
	    	  System.out.println("数据读取超时。");  
	      }
	      System.out.println("from server: " + sb);  
	      writer.close();  
	      br.close();  
	      client.close();  
	   }  
}
客服端就会打印超时;

可能出现的异常 Address already in use: JVM_Bind

最好用netstat -ano查看后、决定是否关闭相应进程或修改端口。

一般解决办法:

1、修改程序端口

2、重启eclipse或javaw.exe

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值