博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
网络编程
阅读量:6082 次
发布时间:2019-06-20

本文共 8772 字,大约阅读时间需要 29 分钟。

hot3.png

Java网络编程之TCP/IP

1.1 TCP/IP协议介绍 TCP/IP是Transmission Control Protocol/Internet Protocol的简写,中文译为传输控制协议/因特网互联协议,又叫做网络通讯协议,由网络层的IP协议和传输层的TCP协议组成,是Internet最基本的协议、Internet国际互联网络的基础,其主要协议如图

160654_PqGA_1775885.png

java TCP/IP编程

服务器端:

public class Server {	private ServerSocket server;	/**	 * 构造方法,用来初始化参数	 */	public Server(){		try {			/*			 * 向系统申请2222端口,			 * 外界可以通过网络发送过来的数据			 */			server=new ServerSocket(2222);		} catch (Exception e) {			e.printStackTrace();		}	}	/**	 * 启动服务器	 */	public void start(){		try {			System.out.println("info: 等待客户端链接......");			Socket socket=server.accept();//io堵塞			System.out.println("info: 客户端"+socket.getLocalAddress().toString()+" 链接上服务器......");			/**			 * 获取客户端的输出流,用于获取从客户端			 */			BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream(), "utf-8"));			String message=null;			while((message=in.readLine())!=null){				System.out.println("客户端 :"+message);			}					} catch (Exception e) {			e.printStackTrace();		}	}	public static void main(String[] args) {		Server server=new Server();		server.start();	}}

 

server=new ServerSocket(2222);//服务器端,监听2222端口,Socket socket=server.accept();//io堵塞 ,等待接受客户端的请求,返回的是客户端的Socket对象,通过Socket对象实现双向通信

客户端:

package com.jsd.jsd1408.chat;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.net.Socket;import java.util.Scanner;/** * @Description: 网络编程案例-客户端 * @author king-pan * @date 2014年10月9日 * @version V1.0 *//* * socket 通常称作"套接字",用来描述ip地址和端口,是一个通信链的句柄 *  * 在internet上的主机一般运行了多个服务软件,同时提供几种服务。 *  * 每种服务都打开一个socket,并绑定到一个端口上, *  * 不同的端口对应于不同的服务。 */public class Client {	/*	 * 客户端运行的socket,用于链接服务器	 */	private Socket socket;	/**	 * 启动客户端	 */	public Client(){		try {			socket=new Socket("localhost", 2222);		} catch (Exception e) {			e.printStackTrace();		}	}	/**	 * 启动客户端	 */	public void start(){		try {			/**			 * 在客户端,若我们希望向服务器发送数据			 * 我们就通过客户端的Socket获取输出流			 * 然后向输出流写出数据就行了			 */			//字节流太麻烦			OutputStreamWriter osw=new OutputStreamWriter(socket.getOutputStream(),"UTF-8");			PrintWriter out=new PrintWriter(osw,false);			Scanner scanner=new Scanner(System.in);			String message=null;			while((message=scanner.nextLine())!=null){				out.print(message+"\r\n");				out.flush();				System.out.println("客户端: 发送消息成功");			}			out.close();			scanner.close();		} catch (Exception e) {			e.printStackTrace();		}	}	public static void main(String[] args) {		Client client=new Client();		client.start();	}}

socket=new Socket("localhost", 2222);//连接指定ip:port 的服务器然后通过socket的输出,输入流实现双向通信

改进代码:

服务器端:

package com.jsd.jsd1408.chat;import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.net.ServerSocket;import java.net.Socket;import java.util.ArrayList;import java.util.List;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class ServerForm {	private ServerSocket server;	/*	 * 连接池,用来控制和管理与客户端交互的线程	 */	private ExecutorService threadPool;	/*	 * 该集合用来保存当前服务器中所有客户端的输出流 用来实现广播效果。	 */	private List
 allOut; /**  * 构造方法,用来初始化参数  */ public ServerForm() { try { /*  * 初始化用来存放所有客户端输出流的集合  */ allOut = new ArrayList
(); allOut = Collections.synchronizedList(allOut); /*  * 向系统申请2222端口, 外界可以通过网络发送过来的数据  */ server = new ServerSocket(2222); /*  * 初始化线程池  */ threadPool = Executors.newFixedThreadPool(50); } catch (Exception e) { e.printStackTrace(); } } /*  * 下面三个方法:  * 1:向集合中添加输出流  * 2:从集合中删除输出流  * 3:遍历集合  * 这三个操作既要做到分别同步,又要做到三者互斥  * 这是因为多线程需要对这个集合做这三个操作。对于  * 线程安全的集合而言,自身是可以做到add,remove  * 互斥的。并且保证方法同步。但是无法做到与遍历进行  * 互斥。所以我们需要自己来维护三个操作的互斥关系。  */ /**  * 将给定的输出流存入共享集合allOut  *   * @param pw  */ public synchronized void addOut(PrintWriter pw) { // 将给定的流存入集合 allOut.add(pw); } /**  * 将给定的输出流从共享集合中删除  *   * @param pw  */ public synchronized void removeOut(PrintWriter pw) { // 将给定的流从集合中删除 allOut.remove(pw); } /**  * 将给定的消息发送给每一个客户端  *   * @param message  */ public synchronized void sendMessageToAllClient(String message) { /*  * 遍历集合,将给定的字符串发送给每一个输出流 从而达到广播消息的效果  */ for (PrintWriter pw : allOut) { pw.println(message); } } /**  * 启动服务器  */ public void start() { try { while (true) { System.out.println("info: 等待客户端链接......"); Socket socket = server.accept();// io堵塞 System.out .println("info: 客户端" + socket.getLocalAddress().toString() + " 链接上服务器......"); /*  * 当一个客户端链接后,我们启动一个线程, 并将该客户端的Socket传入到线程里,使得  * 让该线程来完成与当前客户端的交互工作。 这样我们就可以再次调用accept方法等待 其他客户端的链接了。  */ GetClientHandler handler = new GetClientHandler(socket); // Thread t = new Thread(handler); // t.start(); /*  * 将任务交给线程池  */ threadPool.execute(handler); } } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { Server server = new Server(); server.start(); } /**  * 该线程体的作用是针对给定的客户端进行交互操作 实际工作用于接受客户端的消息并做处理  *   * @author Administrator  *  */ class GetClientHandler implements Runnable { /*  * 该线程用于交互的客户端的Socket  */ private Socket socket; public GetClientHandler(Socket socket) { this.socket = socket; } public void run() { PrintWriter pw = null; try { /*  * 通过Socket获取输出流,用于将消息 发送给客户端  */ OutputStream out = socket.getOutputStream(); OutputStreamWriter osw = new OutputStreamWriter(out, "UTF-8"); pw = new PrintWriter(osw, true); /*  * 将当前线程交互的客户端的输出流存入 共享集合,以便于可以广播消息给当前 客户端  */ addOut(pw); /*  * 通过Socket获取输入流 然后将输入流转换为缓冲字符输入流 循环读取该客户端发送过来的消息  */ InputStream in = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(in, "UTF-8"); BufferedReader br = new BufferedReader(isr); String message = null; /*  * 这里判断读取的内容是不是null是出于对linux 与windows底层实现细节的差异 当客户端与服务端断开链接后  * 若客户端是linux用户,那么服务端的br.readLine() 方法会返回null,返回null对于缓冲流而言也是表示再  * 没有消息可以读取了。所以就应当停止读取工作了。 但是windows的客户端若断开链接,则br.readLine()  * 方法会直接抛出异常。  */ while ((message = br.readLine()) != null) { // System.out.println("客户端说:"+message); // 将消息发送至客户端 // pw.println(message); /*  * 当该客户端发送一条消息过来后,我们将该 消息转发给所有客户端,达到广播的效果  */ sendMessageToAllClient(message); } } catch (Exception e) { e.printStackTrace(); } finally { try { /*  * 当客户端与服务端断开连接后,先将 该客户端的输出流从共享集合中删除 停止对该客户端广播消息  */ removeOut(pw); /*  * 当客户端与服务端断开链接后 服务端这边也应当将Socket关闭 以释放资源  */ if (socket != null) { socket.close(); } } catch (Exception e2) { e2.printStackTrace(); } } } }}

   服务器端,循环接受客户端请求,把每个客户端请求交给一个线程,然后让线程去负责该客户端。

  

客户端:

package com.jsd.jsd1408.chat;import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.net.Socket;import java.util.Scanner;/** * @Description: 网络编程案例-客户端 * @author king-pan * @date 2014年10月9日 * @version V1.0 *//* * socket 通常称作"套接字",用来描述ip地址和端口,是一个通信链的句柄 *  * 在internet上的主机一般运行了多个服务软件,同时提供几种服务。 *  * 每种服务都打开一个socket,并绑定到一个端口上, *  * 不同的端口对应于不同的服务。 */public class ClientForm {	/*	 * 客户端运行的socket,用于链接服务器	 */	private Socket socket;	/**	 * 启动客户端	 */	public ClientForm() {		try {			socket = new Socket("localhost", 2222);		} catch (Exception e) {			e.printStackTrace();		}	}	/**	 * 客户端开始工作的方法	 */	public void start() {		try {			/*			 * 启动客户端中用来读取服务端发送消息的线程			 */			GetServerMessageHandler handler = new GetServerMessageHandler();			Thread t = new Thread(handler);			t.start();			/*			 * 在客户端,若我们希望向服务端发送数据 我们就通过客户端这边的Socket获取 输出流,然后向输出流写出数据就可以了			 */			OutputStream out = socket.getOutputStream();			OutputStreamWriter osw = new OutputStreamWriter(out, "UTF-8");			PrintWriter pw = new PrintWriter(osw, true);			// 创建一个Scanner用于获取用户输入			Scanner scanner = new Scanner(System.in);			System.out.println("信息提示 :   请输入聊天昵称 ......");			pw.println(scanner.nextLine());			/*			 * 将字符串发送至服务端			 */			while (true) {				pw.println(scanner.nextLine());			}		} catch (Exception e) {			e.printStackTrace();		}	}	public static void main(String[] args) {		ClientForm client = new ClientForm();		client.start();	}	/**	 * 该线程的作用是用于接收服务端发送过来的信息 并输出到客户端的控制台上	 * 	 * @author Administrator	 *	 */	class GetServerMessageHandler implements Runnable {		public void run() {			try {				/*				 * 1.通过Socket获取输入流 2.转换为缓冲字符输入流 3.循环读取服务端发送的消息并输出到 控制台				 */				InputStream in = socket.getInputStream();				InputStreamReader isr = new InputStreamReader(in, "UTF-8");				BufferedReader br = new BufferedReader(isr);				String message = null;				while ((message = br.readLine()) != null) {					System.out.println(message);				}			} catch (Exception e) {				e.printStackTrace();			}		}	}}

  客户端连接上服务器,然后与服务器交互

  需要注意的是,使用PrintWrite 的println(),print(),write()方法,print(),write(); 需要在输出的内容后面加上"\r\n"表示该行结束。

转载于:https://my.oschina.net/KingPan/blog/326841

你可能感兴趣的文章
Hibernate 表连接hql语句
查看>>
Journey
查看>>
linux php文件include失败 一个很神奇的问题
查看>>
2018.3.10 模拟赛——(3)平台
查看>>
用HTML,css完成的百叶窗效果,新手必看
查看>>
跨域访问技术CORS(Cross-Origin Resource Sharing)简介
查看>>
COOK50小结
查看>>
JS使用正则表达式过滤多个词语
查看>>
知企业网上线了
查看>>
图形界面报错“已拒绝X11转移申请”的解决方法
查看>>
MongoDB整理笔记のDump & Restore
查看>>
如何获取codeforces的完整数据?(玄学方法)
查看>>
SSH无密码登陆
查看>>
拓扑图弹力布局呈现Flickr图片搜索结果
查看>>
分享数百个 HT 工业互联网 2D 3D 可视化应用案例
查看>>
享元模式(Flyweight)
查看>>
5-19 求链式线性表的倒数第K项 (20分)
查看>>
linux NFS 配置
查看>>
站立会议7
查看>>
linux客户端传输文件到Windows本地
查看>>