Java网络编程上之Socket服务端编程

2/10/2017来源:ASP.NET技巧人气:2015

本篇幅是java网络编程的上篇:socket服务端编程,还有下篇:socket客户端编程。废话不多说,开整。

简单来说,网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向的链路的一段成为一个socket。socket通常用来实现客户端和服务端的连接,一个socket由一个ip地址和一个端口号唯一确定。 使用socket进行通讯的一般连接过程:服务端监听某个端口是否有连接请求,客户端向服务端发出连接请求,服务端向客户端发回接收消息这样就建立了一个连接。服务端和客户端都可以通过发送、写入等方法与对方通信。 下面的是一个实现可以被多个客户端访问,当其中一个客户端失去连接,对其他客户端不会产生影响的一个功能。(这就需要ServerSocket不能关闭,并且需要结合多线程来一起调用)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PRintStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server4 {

	public static void main(String[] args) {
		ServerSocket ss = null;// 服务器端
		try {
			// 服务器端建立连接,端口号为10000
			ss = new ServerSocket(10000);
			// 服务器端不断接受客户端的请求
			while (true) {
				Socket s = ss.accept();
				new Start(s).start();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	static class Start extends Thread {

		Socket s = null;// 客户端
		InputStream in = null;// 输入流
		OutputStream out = null;// 输出流
		BufferedReader reader = null;// 缓冲流
		PrintStream print = null;// 输出流

		/**
		 * 有参构造函数
		 * 
		 * @param s
		 */
		public Start(Socket s) {
			this.s = s;
		}

		@Override
		public void run() {
			super.run();
			try {
				// 从客户端获取输入流,用于读取客户端数据
				in = s.getInputStream();
				// 向客户端写数据
				out = s.getOutputStream();
				reader = new BufferedReader(new InputStreamReader(in, "GB2312"));
				print = new PrintStream(out,true,"GB2312");
				while (true) {
					// 客户端不断输入
					String clientStr = reader.readLine();
					System.out.println("客户端的字符串:" + clientStr);
					if (clientStr.trim().equalsIgnoreCase("exit")) {
						break;
					}
					String outputStr = clientStr + ",你好!";
					print.println(outputStr);
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				try {
					print.close();
					reader.close();
					s.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
		}

	}

}
运行效果:





















如果想实现让多有客户端都能接收到服务端输出的信息,还需要做一下修改(采用集合形式将所有的客户端收集,然后再把信息同一地发送给所有的客户端):
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class Server5 {

	//用来保存所有的客户端的列表
	private static List<Socket> sockets = new ArrayList<Socket>();
	
	public static void main(String[] args) {
		new Server5().startServer();
	}

	private void startServer() {
		ServerSocket ss = null;// 服务器端
		try {
			// 服务器端建立连接,端口号为10000
			ss = new ServerSocket(10000);
			// 服务器端不断接受客户端的请求
			while (true) {
				Socket s = ss.accept();
				sockets.add(s);
				//启动一个线程
				new Start(s).start();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

	 class Start extends Thread {

		Socket s = null;// 客户端
		InputStream in = null;// 输入流
		BufferedReader reader = null;// 缓冲流

		/**
		 * 有参构造函数
		 * 
		 * @param s
		 */
		public Start(Socket s) {
			this.s = s;
		}

		@Override
		public void run() {
			super.run();
			try {
				// 从客户端获取输入流,用于读取客户端数据
				in = s.getInputStream();
				reader = new BufferedReader(new InputStreamReader(in, "GB2312"));
				while (true) {
					// 客户端不断输入
					String clientStr = reader.readLine();
					System.out.println("客户端的字符串:" + clientStr);
					if (clientStr.trim().equalsIgnoreCase("exit")) {
						break;
					}
					String outputStr = clientStr + ",你好!";
					for (Socket s : sockets) {
						//向所有的客户端写数据
						OutputStream out = s.getOutputStream();// 输出流
						PrintStream print = new PrintStream(out,true,"GB2312");
						print.println(outputStr);
					}
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				try {
					reader.close();
					s.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
		}

	}

}



以上的测试需要用到windows的telnet,对于有的小伙伴可能电脑还没有开启该功能,在cmd里输入telnet localhost 10000(localhost:本地 10000:端口号)会提示”不是内部或外部的命令,也不是可运行的程序“。这需要我们来手动打开。具体的方法可以参考这个链接;