JAVA核心技术:Java网络编程

知识点

网络基础知识

ip地址

每个网卡/机器都有一个或多个IP地址

  • IPV4:192.168.0.100,每段从0到255
  • IPV6: FE80:0000:0000:0000:AAAA:0000:00C2:0002
    128bit长,分成8段,每段4个16进制数
  • 查询:Windows平台ipconfig, Linux/Mac平台ifconfig

在这里插入图片描述

端口

port:端口,0-65535

  • 0~1023,OS已经占用了,80是Web,23是telnet
  • 1024~65535,一般程序可使用(谨防冲突)
    • 两台机器通讯就是在IP+Port上进行的
    • 在Windows/Linux/Mac上都可以通过netstat -an来查询
      在这里插入图片描述

公网和内网

公网:万维网/互联网
内网:局域网

  • 网络是分层的
  • 最外层是公网/互联网
  • 底下的每层都是内网
  • ip地址可以在每个层次的网重用
  • tracert 看当前机器和目标机器的访问中继

在这里插入图片描述

通讯协议:TCP和UDP

TCP(Transmission Control Protocol)

  • 传输控制协议,面向连接的协议
  • 两台机器的可靠无差错的数据传输
  • 双向字节流传递
    UDP(User Datagram Protocol)
  • 用户数据报协议,面向无连接协议
  • 不保证可靠的数据传输
  • 速度快,也可以在较差网络下使用

在这里插入图片描述

Java UDP编程

基础知识

  • 计算机通讯:数据从一个IP的port出发(发送方),运输到另外一个IP的port(接收方)
  • UDP:无连接无状态的通讯协议,
    • 发送方发送消息,如果接收方刚好在目的地,则可以接受。如果不在,那这个消息就丢失了
    • 发送方也无法得知是否发送成功
    • UDP的好处就是简单,节省,经济

实现类

  • DatagramSocket:通讯的数据管道
    • send 和receive方法
    • (可选,多网卡)绑定一个IP和Port

在这里插入图片描述

  • DatagramPacket
    • 集装箱:封装数据
    • 地址标签:目的地IP+Port

示例代码

UdpRecv
import java.net.*;
public class UdpRecv
{
	public static void main(String[] args) throws Exception
	{
		DatagramSocket	ds=new DatagramSocket(3000);
		byte [] buf=new byte[1024];
		DatagramPacket dp=new DatagramPacket(buf,1024);
		
		System.out.println("UdpRecv: 我在等待信息");
		ds.receive(dp);//收到消息则封装到dp,否则阻塞
		System.out.println("UdpRecv: 我接收到信息");
		String strRecv=new String(dp.getData(),0,dp.getLength()) +
		" from " + dp.getAddress().getHostAddress()+":"+dp.getPort(); 
		System.out.println(strRecv);
		
		Thread.sleep(1000);
		System.out.println("UdpRecv: 我要发送信息");
		String str="hello world 222";
		DatagramPacket dp2=new DatagramPacket(str.getBytes(),str.length(), 
				InetAddress.getByName("127.0.0.1"),dp.getPort());
		ds.send(dp2);
		System.out.println("UdpRecv: 我发送信息结束");
		ds.close();
	}
}

在这里插入图片描述

UdpSend
import java.net.*;
public class UdpSend
{
	public static void main(String [] args) throws Exception
	{
		DatagramSocket ds=new DatagramSocket();
		String str="hello world";
		DatagramPacket dp=new DatagramPacket(str.getBytes(),str.length(),
				InetAddress.getByName("127.0.0.1"),3000);//本机的3000端口
		
		System.out.println("UdpSend: 我要发送信息");
		ds.send(dp);
		System.out.println("UdpSend: 我发送信息结束");
		
		Thread.sleep(1000);
		byte [] buf=new byte[1024];
		DatagramPacket dp2=new DatagramPacket(buf,1024);
		System.out.println("UdpSend: 我在等待信息");
		ds.receive(dp2);
		System.out.println("UdpSend: 我接收到信息");
		String str2=new String(dp2.getData(),0,dp2.getLength()) +
				" from " + dp2.getAddress().getHostAddress()+":"+dp2.getPort(); 
		System.out.println(str2);
				
		ds.close();
	}
}

UdpSend

在这里插入图片描述
UdpRecv

在这里插入图片描述

接收方必须早于发起方执行

Java TCP 编程

基础知识

TCP协议:有链接、保证可靠的无误差通讯

① 服务器:创建一个ServerSocket,等待连接

软件服务器有两个要求:

  1. 它能够实现一定的功能
  2. 它必须在一个公开地址上对外提供服务

② 客户机:创建一个Socket,连接到服务器
③ 服务器:ServerSocket接收到连接,创建一个Socket和客户的Socket建立专线连接,后续服务器和客户机的对话(这一对Socket)会在一个单独的线程(服务器端)上运行
④ 服务器的ServerSocket继续等待连接,返回①

在这里插入图片描述

实现类

  • ServerSocket: 服务器码头
    • 需要绑定port
    • 如果有多块网卡,需要绑定一个IP地址
  • Socket: 运输通道
    • 客户端需要绑定服务器的地址和Port
    • 客户端往Socket输入流写入数据,送到服务端
    • 客户端从Socket输出流取服务器端过来的数据
    • 服务端反之亦然
    • 服务端等待响应时,处于阻塞状态
    • 服务端可以同时响应多个客户端
    • 服务端每接受一个客户端,就启动一个独立的线程与之对应
    • 客户端或者服务端都可以选择关闭这对Socket的通道

示例代码

TcpServer和TcpClint交互
//TcpServer.java
import java.net.*;
import java.io.*;
public class TcpServer
{
	public static void main(String [] args) 
	{
		try
		{
			ServerSocket ss=new ServerSocket(8001); //驻守在8001端口
			Socket s=ss.accept();                   //阻塞,等到有客户端连接上来
			System.out.println("welcome to the java world");
			InputStream ips=s.getInputStream();     //有人连上来,打开输入流
			OutputStream ops=s.getOutputStream();   //打开输出流
			//同一个通道,服务端的输出流就是客户端的输入流;服务端的输入流就是客户端的输出流
			
			ops.write("Hello, Client!".getBytes());  //输出一句话给客户端
			
			
			BufferedReader br = new BufferedReader(new InputStreamReader(ips));
			//从客户端读取一句话			
			System.out.println("Client said: " + br.readLine());
			
			
			ips.close();          
			ops.close();
			s.close();
			ss.close();
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
}
//TcpClient.java
import java.net.*;
import java.io.*;

public class TcpClient {
	public static void main(String[] args) {
		try {
			Socket s = new Socket(InetAddress.getByName("127.0.0.1"), 8001); //需要服务端先开启
			
			//同一个通道,服务端的输出流就是客户端的输入流;服务端的输入流就是客户端的输出流
			InputStream ips = s.getInputStream();    //开启通道的输入流
			BufferedReader brNet = new BufferedReader(new InputStreamReader(ips));
			
			OutputStream ops = s.getOutputStream();  //开启通道的输出流
			DataOutputStream dos = new DataOutputStream(ops);			

			BufferedReader brKey = new BufferedReader(new InputStreamReader(System.in));  //封装键盘输入
			while (true) 
			{
				String strWord = brKey.readLine();
				if (strWord.equalsIgnoreCase("quit"))
				{
					break;
				}
				else
				{
					System.out.println("I want to send: " + strWord);
					dos.writeBytes(strWord + System.getProperty("line.separator"));
					
					System.out.println("Server said: " + brNet.readLine());
				}
				
			}
			
			dos.close();
			brNet.close();
			brKey.close();
			s.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

在这里插入图片描述

多个客户端对应一个服务端
//TcpServer2.java
import java.net.*;
public class TcpServer2
{
	public static void main(String [] args)
	{
		try
		{
			ServerSocket ss=new ServerSocket(8001);
			while(true)
			{
				Socket s=ss.accept();
				System.out.println("来了一个client");
				new Thread(new Worker(s)).start();
			}
			//ss.close();
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
}
import java.net.*;
import java.io.*;

class Worker implements Runnable {
	Socket s;

	public Worker(Socket s) {
		this.s = s;
	}

	public void run() {
		try {
			System.out.println("服务人员已经启动");
			InputStream ips = s.getInputStream();
			OutputStream ops = s.getOutputStream();

			BufferedReader br = new BufferedReader(new InputStreamReader(ips));
			DataOutputStream dos = new DataOutputStream(ops);
			while (true) {
				String strWord = br.readLine();
				System.out.println("client said:" + strWord +":" + strWord.length());
				if (strWord.equalsIgnoreCase("quit"))
					break;
				String strEcho = strWord + " 666";
				// dos.writeBytes(strWord +"---->"+ strEcho +"\r\n");
				System.out.println("server said:" + strWord + "---->" + strEcho);
				dos.writeBytes(strWord + "---->" + strEcho + System.getProperty("line.separator"));
			}
			br.close();
			// 关闭包装类,会自动关闭包装类中所包装的底层类。所以不用调用ips.close()
			dos.close();
			s.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

在这里插入图片描述

Java HTTP 编程

网页访问

网页是特殊的网络服务(HTTP, Hypertext Transfer Protocol)

  • 在浏览器输入URL地址
  • 浏览器将连接到远程服务器上(IP+80Port)
  • 请求下载一个HTML文件下来,放到本地临时文件夹中
  • 在浏览器显示出来

HTTP

  • 超文本传输协议(HyperText Transfer Protocol)
  • 用于从WWW(World Wide Web)服务器传输超文本到本地浏览器的传输协议
  • 1989年蒂姆•伯纳斯•李(Tim Berners Lee)提出了一种能让远隔两地的研究者们共享知识的设想
  • 借助多文档之间相互关联形成的超文本 (HyperText),连成可相互参阅的 WWW
    – 1990年问世,1997年发布版本1.1,2015年发布版本2.0
    – 资源文件采用HTML编写,以URL形式对外提供

HTML

在这里插入图片描述

HTTP访问方式

  • GET:从服务器获取资源到客户端
  • POST:从客户端向服务器发送数据
  • PUT:上传文件
  • DELETE:删除文件
  • HEAD:报文头部
  • OPTIONS:询问支持的方法
  • TRACE:追踪路径
  • CONNECT:用隧道协议连接代理

HTTP编程

Java HTTP编程 (java.net包)

  • 支持模拟成浏览器的方式去访问网页
  • URL,Uniform Resource Locator,代表一个资源
  • URLConnection
    • 获取资源的连接器
    • 根据URL的openConnection()方法获URLConnection
    • connect方法,建立和资源的联系通道
    • getInputStream方法,获取资源的内容

示例代码

Get
import java.io.*;
import java.net.*;
import java.util.*;


public class URLConnectionGetTest
{
   public static void main(String[] args)
   {
      try
      {
         String urlName = "http://www.baidu.com";

         URL url = new URL(urlName);
         URLConnection connection = url.openConnection(); 
         connection.connect();

         // 打印http的头部信息

         Map<String, List<String>> headers = connection.getHeaderFields();
         for (Map.Entry<String, List<String>> entry : headers.entrySet())
         {
            String key = entry.getKey();
            for (String value : entry.getValue())
               System.out.println(key + ": " + value);
         }

         // 输出将要收到的内容属性信息

         System.out.println("----------");
         System.out.println("getContentType: " + connection.getContentType());
         System.out.println("getContentLength: " + connection.getContentLength());
         System.out.println("getContentEncoding: " + connection.getContentEncoding());
         System.out.println("getDate: " + connection.getDate());
         System.out.println("getExpiration: " + connection.getExpiration());
         System.out.println("getLastModifed: " + connection.getLastModified());
         System.out.println("----------");

         BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));

         // 输出收到的内容
         String line = "";
         while((line=br.readLine()) != null)
         {
        	 System.out.println(line);
         }
         br.close();
      }
      catch (IOException e)
      {
         e.printStackTrace();
      }
   }
}

在这里插入图片描述

Post
import java.io.*;
import java.net.*;
import java.nio.file.*;
import java.util.*;

public class URLConnectionPostTest
{
   public static void main(String[] args) throws IOException
   {
      String urlString = "https://tools.usps.com/go/ZipLookupAction.action";
      Object userAgent = "HTTPie/0.9.2";
      Object redirects = "1";
      CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
      
      Map<String, String> params = new HashMap<String, String>();
      params.put("tAddress", "1 Market Street");  
      params.put("tCity", "San Francisco");
      params.put("sState", "CA");
      String result = doPost(new URL(urlString), params, 
         userAgent == null ? null : userAgent.toString(), 
         redirects == null ? -1 : Integer.parseInt(redirects.toString()));
      System.out.println(result);
   }   

   public static String doPost(URL url, Map<String, String> nameValuePairs, String userAgent, int redirects)
         throws IOException
   {        
      HttpURLConnection connection = (HttpURLConnection) url.openConnection();
      if (userAgent != null)
         connection.setRequestProperty("User-Agent", userAgent);
      
      if (redirects >= 0)
         connection.setInstanceFollowRedirects(false);
      
      connection.setDoOutput(true);
      
      //输出请求的参数
      try (PrintWriter out = new PrintWriter(connection.getOutputStream()))
      {
         boolean first = true;
         for (Map.Entry<String, String> pair : nameValuePairs.entrySet())
         {
        	//参数必须这样拼接 a=1&b=2&c=3
            if (first) 
            {
            	first = false;
            }
            else
            {
            	out.print('&');
            }
            String name = pair.getKey();
            String value = pair.getValue();
            out.print(name);
            out.print('=');
            out.print(URLEncoder.encode(value, "UTF-8"));
         }
      }      
      String encoding = connection.getContentEncoding();
      if (encoding == null) 
      {
    	  encoding = "UTF-8";
      }
            
      if (redirects > 0)
      {
         int responseCode = connection.getResponseCode();
         System.out.println("responseCode: " + responseCode);
         if (responseCode == HttpURLConnection.HTTP_MOVED_PERM 
               || responseCode == HttpURLConnection.HTTP_MOVED_TEMP
               || responseCode == HttpURLConnection.HTTP_SEE_OTHER) 
         {
            String location = connection.getHeaderField("Location");
            if (location != null)
            {
               URL base = connection.getURL();
               connection.disconnect();
               return doPost(new URL(base, location), nameValuePairs, userAgent, redirects - 1);
            }
            
         }
      }
      else if (redirects == 0)
      {
         throw new IOException("Too many redirects");
      }
      
      //接下来获取html 内容
      StringBuilder response = new StringBuilder();
      try (Scanner in = new Scanner(connection.getInputStream(), encoding))
      {
         while (in.hasNextLine())
         {
            response.append(in.nextLine());
            response.append("\n");
         }         
      }
      catch (IOException e)
      {
         InputStream err = connection.getErrorStream();
         if (err == null) throw e;
         try (Scanner in = new Scanner(err))
         {
            response.append(in.nextLine());
            response.append("\n");
         }
      }

      return response.toString();
   }
}

当URL中包含特殊字符(空格、汉字、特殊符号等),需要采用URLEncoder。encode方法进行转义。

HTTP状态返回码:
200,请求成功;
404,请求失败;
500,服务器错误;
·······

在这里插入图片描述

Java HTTP 编程 (HttpClient)

HttpClient

  • JDK HTTP Client (JDK自带,从9开始)
  • Apache HttpComponents的HttpClient (Apache出品)
JDK HttpClient
  • JDK 9 新增,JDK10更新,JDK11正式发布
  • java.net.http包
  • 取代URLConnection
  • 支持HTTP/1.1和HTTP/2
  • 实现大部分HTTP方法
  • 主要类
    • HttpClient
    • HttpRequest
    • HttpResponse

示例代码

Get

import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.Charset;

public class JDKHttpClientGetTest {

	public static void main(String[] args) throws IOException, InterruptedException {
		doGet();
	}
	
	public static void doGet() {
		try{
			HttpClient client = HttpClient.newHttpClient();
			HttpRequest request = HttpRequest.newBuilder(URI.create("http://www.baidu.com")).build();
			HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
			System.out.println(response.body());
		}
		catch(Exception e) {
			e.printStackTrace();
		}
	}
}

在这里插入图片描述
Post

import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class JDKHttpClientPostTest {

	public static void main(String[] args) throws IOException, InterruptedException {
		doPost();
	}
	
	public static void doPost() {
		try {
			HttpClient client = HttpClient.newBuilder().build();
			HttpRequest request = HttpRequest.newBuilder()
					.uri(URI.create("https://tools.usps.com/go/ZipLookupAction.action"))
					//.header("Content-Type","application/x-www-form-urlencoded")
					.header("User-Agent", "HTTPie/0.9.2")
					.header("Content-Type","application/x-www-form-urlencoded;charset=utf-8")
					//.method("POST", HttpRequest.BodyPublishers.ofString("tAddress=1 Market Street&tCity=San Francisco&sState=CA"))
					//.version(Version.HTTP_1_1)
					.POST(HttpRequest.BodyPublishers.ofString("tAddress=" 
					    + URLEncoder.encode("1 Market Street", "UTF-8") 
					    + "&tCity=" + URLEncoder.encode("San Francisco", "UTF-8") + "&sState=CA"))
					//.POST(HttpRequest.BodyPublishers.ofString("tAddress=" + URLEncoder.encode("1 Market Street", "UTF-8") + "&tCity=" + URLEncoder.encode("San Francisco", "UTF-8") + "&sState=CA"))
					.build();
			HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
			System.out.println(response.statusCode());
			System.out.println(response.headers());
			System.out.println(response.body().toString());

		}
		catch(Exception e) {
			e.printStackTrace();
		}
	}	
}

在这里插入图片描述

HttpComponents
  • hc.apache.org, Apache出品
  • 从HttpClient进化而来
  • 是一个集成的Java HTTP工具包
    • 实现所有HTTP方法:get/post/put/delete
    • 支持自动转向
    • 支持https协议
    • 支持代理服务器等

示例代码

Get

import java.io.IOException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class HttpComponentsGetTest {

    public final static void main(String[] args) throws Exception {
    	
    	CloseableHttpClient httpClient = HttpClients.createDefault();
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(5000)   //设置连接超时时间
                .setConnectionRequestTimeout(5000) // 设置请求超时时间
                .setSocketTimeout(5000)
                .setRedirectsEnabled(true)//默认允许自动重定向
                .build();
        
        HttpGet httpGet = new HttpGet("http://www.baidu.com");
        httpGet.setConfig(requestConfig);
        String srtResult = "";
        try {
            HttpResponse httpResponse = httpClient.execute(httpGet);
            if(httpResponse.getStatusLine().getStatusCode() == 200){
                srtResult = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");//获得返回的结果                
                System.out.println(srtResult);
            }else
            {
                //异常处理
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

在这里插入图片描述
Post

import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

public class HttpComponentsPostTest {

    public final static void main(String[] args) throws Exception {
    	
    	//获取可关闭的 httpCilent
        //CloseableHttpClient httpClient = HttpClients.createDefault();
    	CloseableHttpClient httpClient = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategy()).build();
    	//配置超时时间
        RequestConfig requestConfig = RequestConfig.custom().
                setConnectTimeout(10000).setConnectionRequestTimeout(10000)
                .setSocketTimeout(10000).setRedirectsEnabled(false).build();
         
        HttpPost httpPost = new HttpPost("https://tools.usps.com/go/ZipLookupAction.action");
        //设置超时时间
        httpPost.setConfig(requestConfig);
        
        //装配post请求参数
        List<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>(); 
        list.add(new BasicNameValuePair("tAddress", URLEncoder.encode("1 Market Street", "UTF-8")));  //请求参数
        list.add(new BasicNameValuePair("tCity", URLEncoder.encode("San Francisco", "UTF-8"))); //请求参数
        list.add(new BasicNameValuePair("sState", "CA")); //请求参数
        try {
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list,"UTF-8"); 
            //设置post求情参数
            httpPost.setEntity(entity);
            httpPost.setHeader("User-Agent", "HTTPie/0.9.2");
            //httpPost.setHeader("Content-Type","application/form-data");
            HttpResponse httpResponse = httpClient.execute(httpPost);
            String strResult = "";
            if(httpResponse != null){ 
                System.out.println(httpResponse.getStatusLine().getStatusCode());
                if (httpResponse.getStatusLine().getStatusCode() == 200) {
                    strResult = EntityUtils.toString(httpResponse.getEntity());
                }
                else {
                    strResult = "Error Response: " + httpResponse.getStatusLine().toString();
                } 
            }else{
                 
            }
            System.out.println(strResult);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if(httpClient != null){
                    httpClient.close(); //释放资源
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

在这里插入图片描述

练习

请编写一个群聊的程序,包括服务端程序和客户端程序。

服务端功能:收到某客户端的信息,将消息在控制台输出,然后,发给其他另外的客户端。

客户端功能:每隔5秒发送一条信息给服务端。然后接收服务器转发过来的消息,并在控制台输出。

要求:最后提交程序源码和运行截图。运行截图在一个画面上,包括服务端截图和2个客户端的截图。

import java.net.*;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
public class ChatRoomServer {
	public static void main(String[] args) {
		   //线程池
		   ThreadPoolExecutor executor=(ThreadPoolExecutor)Executors.newFixedThreadPool(4);
		   List<Socket> slist=new ArrayList<Socket>();
		   int num=0;
		   try { 
			   ServerSocket ss=new ServerSocket(8001);
			   while(true) {
				   Socket s=ss.accept();
				   slist.add(s);
				   System.out.println("来了一个Client");
				   executor.execute(new Worker(s,slist,num));
				   num++;
			   }
		   }catch(Exception e) {
			   e.printStackTrace();
		   }
	   }
}
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.util.List;
 
class Worker implements Runnable{
    Socket s;
    List<Socket> slist;
    int num;
    
    public Worker(Socket s,List<Socket> slist,int num) {
    	this.s=s;
    	this.slist=slist;
        this.num=num;    	
    }
	@Override
	public void run() {
		try {
			System.out.println("服务人员已经启动");
			InputStream ips=s.getInputStream();
			BufferedReader br=new BufferedReader(new InputStreamReader(ips));
			
			
			while(true) {
				String strWord=br.readLine();
				System.out.println("No."+num+" client said:"+strWord+":"+strWord.length());
				if(strWord.equals("quit")) {
					break;
				}
				if(strWord!=null) {
				for(int i=0;i<slist.size();i++) {
					if(i!=num) {
						Socket sc=slist.get(i);
						OutputStream ops=sc.getOutputStream();
						DataOutputStream dos=new DataOutputStream(ops);
						System.out.println("No."+num+" client said "+strWord);
						dos.writeBytes("No."+num+" client said "+strWord+System.getProperty("line.separator"));
					}
				}
				}	
			}
			br.close();
			//关闭包装类,会自动关闭包装类的底层类。所以不用调用ips.close()
			
			s.close();
		}catch(Exception e) {
			e.printStackTrace();
		}
		
	}
    
}
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

public class ChatClient {
	public static void main(String[] args) {
		try {
			Socket s = new Socket(InetAddress.getByName("127.0.0.1"), 8001); //需要服务端先开启
			
			//同一个通道,服务端的输出流就是客户端的输入流;服务端的输入流就是客户端的输出流
			InputStream ips = s.getInputStream();    //开启通道的输入流
			BufferedReader brNet = new BufferedReader(new InputStreamReader(ips));
			
			OutputStream ops = s.getOutputStream();  //开启通道的输出流
			DataOutputStream dos = new DataOutputStream(ops);			
			
			String msg="6666";
			while(true) {
				Thread.sleep(5000);
			
				dos.writeBytes(msg+System.getProperty("line.separator"));
				System.out.println("Server said:"+brNet.readLine());
			}
 
		}catch(Exception e) {
			e.printStackTrace();
		}

	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值