您的位置:首页 > 理论基础 > 计算机网络

java网络socket编程(三)之ServerSocket服务器端

2016-07-13 18:43 1411 查看

一、简介

java提供了一个ServerSocket类表示服务器Socket。服务器Socket在服务器上运行,监听入站ftp连接。每个服务器Socket监听服务器上的一个特定端口。当远程注解上的一个客户端尝试这个端口时,服务器就会被唤醒,协商建立客户端与服务器端的连接,并返回一个常规的Socket对象,表示2台主机之间的Socket。也是就说服务器端Socket接受到客户端Socket发送过来的连接时,服务器端会生成一个常规的Socket对象,用于向客户端发送数据,数据总是通过常规socket进行传输。

二、使用ServerSocket类

ServerSocket类包含了使用java编写服务器所需要的全部内容。其中包括创建新ServerSocket对象的构造函数,在指定端口监听客户端的连接的方法、配置各个服务器Socket选项的方法,以及一些其他常用的方法,如toString()。
在java中,Server服务器的基本生命周期包含以下几个:
1.使用一个ServerSocket()构造函数在一个特定的端口创建一个新的ServerSocket对象。
2.ServerSocket使用他的accept()方法来监听这个端口的入站连接。accept会一直阻塞,直到一个客户端尝试与服务器建立连接,此时accept将返回一个连接客户端和服务器Socket对象。
3.根据服务器的类型,会调用Socket对象的getInputStream或getOutputStream方法,或者这两个方法都调用,以获得客户端通信的输入和输出流。
4.服务器和客户端根据已经协商的协议交互,直到要关闭连接。
5.服务器或客户端关闭连接。
5服务器返回到第2不,等待下一次连接。

2.1  一个完整的接收/响应客户端的例子

<span style="font-family:Microsoft YaHei;">import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.ServerSocket;
import java.net.Socket;

/**
* Socket服务器端测试类
* @author zzj
* @date Jul 14, 2016 11:35:32 AM
*/
public class ServerSocketTest {

public static void main(String[] args) {
testCommon();
}

/**
* 1.测试普通的server
* @author zzj
*/
public static void testCommon(){
ServerSocket serverSocket=null;
try {
serverSocket = new ServerSocket(22);
while(true){
System.out.println("wait receive message from client...");
//接收客户端连接的socket对象
Socket connection =null;
try {
//接收客户端传过来的数据,会阻塞
connection=serverSocket.accept();

System.out.println("****received message from client******");

//读取客户端传过来的数据
readMessageFromClient(connection.getInputStream());

System.out.println("****received message from client end******");

//向客户端写入数据
writeMsgToClient(connection.getOutputStream(),"I am server message!!!");

connection.close();
} catch (Exception e) {
e.printStackTrace();
}finally{
if (connection!=null) {
connection .close();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
if (serverSocket!=null) {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

/**
* 读取客户端信息
* @param inputStream
*/
private static void readMessageFromClient(InputStream inputStream) throws IOException {
Reader reader = new InputStreamReader(inputStream);
BufferedReader br=new BufferedReader(reader);
String a = null;
while((a=br.readLine())!=null){
System.out.println(a);
}
}

/**
* 响应客户端信息
* @param outputStream
* @param string
*/
private static void writeMsgToClient(OutputStream outputStream, String string) throws IOException {
Writer writer = new OutputStreamWriter(outputStream);
writer.append("I am server message!!!");
writer.flush();
writer.close();
}
}</span>
<span style="font-family:Microsoft YaHei;">import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;

/**
* Socket客户端
* @author zzj
* @date Jul 13, 2016 2:47:13 PM
*/
public class SocketTest {
public static void main(String[] args) {
writeToServer("localhost",22);
}

/**
* 向服务器写数据
* @param serverHost socket服务器地址
* @param port 端口
* @author zzj
*/
public static void writeToServer(String serverHost,int port){
Socket socket = null;
try {
//1.建立客户端socket连接,指定服务器位置及端口
socket =new Socket("localhost",22);

//2.得到socket读写流
OutputStream os=socket.getOutputStream();
PrintWriter pw=new PrintWriter(os);

//输入流
InputStream is=socket.getInputStream();
BufferedReader br=new BufferedReader(new InputStreamReader(is));

//3.利用流按照一定的操作,对socket进行读写操作
String info="用户名:1,用户密码:1";
pw.write(info);
pw.flush();
socket.shutdownOutput();
//接收服务器的相应
String reply=null;
while(!((reply=br.readLine())==null)){
System.out.println("接收服务器的信息:"+reply);
}
//4.关闭资源
br.close();
is.close();
pw.close();
os.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}finally{
if (socket!=null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
</span>

2.2 多线程接收客户端信息

由于服务器再等待客户端连接并处理时,会处理完一个才会处理下一个,导致资源浪费或者客户端等待时间过长,这里做一次简单的优化,每次收到客户端的请求连接时,就开启一个线程来处理响应,只需要将上面的server代码简单的改下并封装即可:
<span style="font-family:Microsoft YaHei;">**
* Socket服务器端开启线程测试类
* @author zzj
* @date Jul 14, 2016 11:35:32 AM
*/
public class ServerSocketThreadTest  {

public static void main(String[] args) {
testCommon();
}

/**
* 1.测试普通的server
* @author zzj
*/
public static void testCommon(){
ServerSocket serverSocket=null;
try {
serverSocket = new ServerSocket(22);
while(true){
System.out.println("wait receive message from client...");
//接收客户端连接的socket对象
Socket connection =null;
//接收客户端传过来的数据,会阻塞
connection=serverSocket.accept();
new SubThread(connection).start();
}
} catch (Exception e) {
e.printStackTrace();
}finally{
if (serverSocket!=null) {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

class SubThread extends Thread{
private Socket connection;
public SubThread(Socket conSocket){
this.connection=conSocket;
}

public void run(){
try {

System.out.println("****received message from client******");

//读取客户端传过来的数据
readMessageFromClient(connection.getInputStream());

System.out.println("****received message from client end******");
System.out.println();

//向客户端写入数据
writeMsgToClient(connection.getOutputStream(),"I am server message!!!");

connection.close();
} catch (Exception e) {
e.printStackTrace();
}finally{
if (connection!=null) {
try {
connection .close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

/**
* 读取客户端信息
* @param inputStream
*/
private static void readMessageFromClient(InputStream inputStream) throws IOException {
Reader reader = new InputStreamReader(inputStream);
BufferedReader br=new BufferedReader(reader);
String a = null;
while((a=br.readLine())!=null){
System.out.println(a);
}
}

/**
* 响应客户端信息
* @param outputStream
* @param string
*/
private static void writeMsgToClient(OutputStream outputStream, String string) throws IOException {
Writer writer = new OutputStreamWriter(outputStream);
writer.append("I am server message!!!");
writer.flush();
writer.close();
}
}</span>


2.3 线程池的方式改进多并发请求服务器问题

如果每次来一个请求,服务器端开启一个线程的话,有可能在同时来成千上万个请求时导致内存暴增而导致程序的崩溃,为了减轻开启线程导致的内存过高问题,这里采用线程池来缓解这个问题,下面为主要代码:
package com.hq.socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.itextpdf.text.pdf.PdfStructTreeController.returnType;

/**
* Socket服务器端开启线程测试类
* @author zzj
* @date Jul 14, 2016 11:35:32 AM
*/
public class ServerSocketPoolTest  {

public static void main(String[] args) {
testCommon();
}

/**
* 1.测试普通的server
* @author zzj
*/
public static void testCommon(){
ServerSocket serverSocket=null;
//定义一个容量为50的线程
ExecutorService service = Executors.newFixedThreadPool(50);
try {
serverSocket = new ServerSocket(220);
while(true){
System.out.println("wait receive message from client...");
//接收客户端连接的socket对象
Socket connection =null;
//接收客户端传过来的数据,会阻塞
connection=serverSocket.accept();
service.submit(new SubThread(connection));
}
} catch (Exception e) {
e.printStackTrace();
}finally{
if (serverSocket!=null) {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

class SubPolThread implements Callable<Boolean>{
private Socket connection;
public SubPolThread(Socket conSocket){
this.connection=conSocket;
}

/**
* 读取客户端信息
* @param inputStream
*/
private static void readMessageFromClient(InputStream inputStream) throws IOException {
Reader reader = new InputStreamReader(inputStream);
BufferedReader br=new BufferedReader(reader);
String a = null;
while((a=br.readLine())!=null){
System.out.println(a);
}
}

/**
* 响应客户端信息
* @param outputStream
* @param string
*/
private static void writeMsgToClient(OutputStream outputStream, String string) throws IOException {
Writer writer = new OutputStreamWriter(outputStream);
writer.append("I am server message!!!");
writer.flush();
writer.close();
}

/* (non-Javadoc)
* @see java.util.concurrent.Callable#call()
*/
@Override
public Boolean call() throws Exception {
try {

System.out.println("****received message from client******");

//读取客户端传过来的数据
readMessageFromClient(connection.getInputStream());

System.out.println("****received message from client end******");
System.out.println();

//向客户端写入数据
writeMsgToClient(connection.getOutputStream(),"I am server message!!!");

connection.close();
} catch (Exception e) {
e.printStackTrace();
return false;
}finally{
if (connection!=null) {
try {
connection .close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return true;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息