ServerSocker是用于服务器端的,Socket 是建立网络连接时用的。在连接成功时,两端都会产生一个Socket实例,操作这个实例,完成所需的会话。Socket和ServerSocket的交互过程如图,

Socket 和 ServerSocket_客户端

1 Socket类

  socket类为客户端的通信套接字,可以指定远端ip地址,端口号进行连接通信,也可以通过方法获得已连接的Socket的远端ip地址,端口,还可以将此socket以字节输入流和输出流的形式返回,当与数据输入流和输出流绑定,便可以实现客户端的网络通信。

2个常用构造函数 :

  (1) 创建一个socket 并与指定的IP地址的端口相连接。address 为指定的ip , port 为指定的端口 。

Socket(InetAddress address , int port ) ;

 (2) 创建一个socket并与指定主机的指定端口相连接。Host为指定的主机的字符串名;port是指定的端口号。

Socket(String host , int port ) ;

返回输入流和输出流的方法

public InputStream getInputStream() ; 
public OutputStream getOutputStream();

ServerSocket 类

ServerSocket类是服务器的通信套接字,用来侦听客户端的请求连接,并为每个连接创建一个Socket对象,由此创建绑定此Scoket的输入流和输出流,与客户端实现网络通信。

构造函数 

public ServerSocket(int port ) ; // 如果端口号为0,则在任意的空闲端口创建一个服务器套接字
public ServerSocket(int port ,int backlog) ; // backlog :最大的连接数量


Socket 和 ServerSocket_客户端_02

ServerSocket成员方法

 

 

 

 

 

 

 

 

服务端代码

package com.chapter1;//例程4-6网络服务器端程序 DS_Server4_6.java
import java.io.*;
import java.net.*;
public class DS_Server3_1 {
public static final int PORT=8888;
public static void main(String[] args) throws IOException{
ServerSocket s=new ServerSocket(PORT); //建立服务器ServerSocket
System.out.println("服务器套接字信息:"+s);
try{
//程序阻塞,等待连接。即直到有一个客户请求到达,程序方能继续执行
Socket ss=s.accept();//侦听PORT端口,获得客户端套接字
System.out.println("套接字接收到的信息:"+ss);
try {
//连接成功,建立相应的数据输入输出流
DataInputStream dis=new DataInputStream(ss.getInputStream());
DataOutputStream dos=new DataOutputStream(ss.getOutputStream());
//在死循环中,来与客户端通信
while(true){//
String str=dis.readUTF(); //从客户端中读数据
if(str.equals("end"))break; //当读到end时,程序终止
System.out.println(str);
dos.writeUTF("服务器应答:"+str); //向客户端中写数据
}
dos.close(); //关闭输出流对象dos
dis.close(); //关闭输入流对象dis
}finally{
ss.close(); //关闭套接字
}
}finally{
System.out.println("服务器结束……");
s.close(); //关闭服务器套接字
}
}
}

客户端代码 : 

package com.chapter1;//例程4-1网络客户端程序 DS_Client4_1.java
import java.io.*;
import java.net.*;
public class DS_Client1_1 {
public static void main(String[] args) throws IOException{
// ①建立Socket,服务器在本机的8888端口处进行“侦听”
Socket socket =new Socket("127.0.0.1",8888); //建立套接字
System.out.println("客户端套接字信息:"+ socket);
try{ // ②套接字建立成功后,建立字节输入流dis和输出流dos对象
DataInputStream dis=new DataInputStream(socket.getInputStream());
DataOutputStream dos=new DataOutputStream(socket.getOutputStream());
// ③调用其对应方法进行网络通信
for(int i=0;i<6;i++){
// writeUTF 是客户端向服务端发送数据
dos.writeUTF("客户端测试:"+i); //向服务器发数据
dos.flush(); //刷新输出缓冲区,以便立即发送
System.out.println(dis.readUTF()); //将从服务器接收的数据输出
}
dos.writeUTF("end"); //向服务器发送终止标志
dos.flush(); //刷新输出缓冲区,以便立即发送
// ④关闭对象
dos.close(); //关闭输出流对象dos
dis.close(); //关闭输入流对象dis
}finally{
System.out.println("客户端结束……");
socket.close(); //关闭套接字对象socket
}
}
}

 

客户端套接字信息:Socket[addr=/127.0.0.1,port=8888,localport=46798]

port : 是指客户端指定的目标主机的端口号 ;

localport : 是指运行客户端程序的端口号;

本质是其实就是两个主机之间端与端的通信。

多线程的Socket通信实现 

通常服务器会同时处理多个客户端的请求,这时候就用到多线程处理机制。常用的方法就是在服务器程序中调用accept()返回一个socket 后,就用它新建立一个线程,令这个线程为特定的客户服务。

服务器 :

package com.mbp;//例程3-2 多线程服务器端程序MBP_Server3_2.java
import java.net.*;
import java.io.*;
public class MBP_Server3_2 {
public static final int PORT=8889;
public static void main(String[] args) throws IOException{
ServerSocket ss=new ServerSocket(PORT);//创建服务器套接字
System.out.println("服务器开启!");
try{
while(true){
Socket s=ss.accept();//侦听服务器定端口PORT,接收客户端套接字
try{
//启动一个新的线程,并把accept()得到的socket传入新线程中
new ServerOne(s);
}catch(IOException e){
s.close();//关闭接字
}
}
}finally{
ss.close();//关闭服务器套接字
}
}
}
//用于为特定用户服务的线程类
class ServerOne extends Thread{
private Socket s;
private BufferedReader in;
private PrintWriter out;
public ServerOne(Socket s) throws IOException{
this.s=s;
//创建缓冲字符读入器in和字符文本输出流out
in=new BufferedReader(new InputStreamReader(s.getInputStream()));
out=new PrintWriter(new BufferedWriter
(new OutputStreamWriter(s.getOutputStream())),true);
start();//启动
}
public void run(){//线程自动运行
try{
while(true){
String str=in.readLine();//接收客户端信息
if(str.equals("end")) {
System.out.println("服务器:接收来自 "+ s.getInetAddress() + ":" +s.getPort()+"客户端信息:"+str);
out.println("Echo:"+str);//向客户端发送信息
break;}
System.out.println("服务器:接收来自 "+ s.getInetAddress() + ":" +s.getPort()+"客户端信息:"+str);
out.println("Echo:"+str);//向客户端发送信息
}
System.out.println("closing.....");
}catch(IOException e){
}finally{
try{
s.close();//关闭套接字
}catch(IOException e){}
}
}
}

客户端

package com.mbp;//例程3-3 多线程客户端程序MBP_Client3_3.java
import java.net.*;
import java.io.*;
public class MBP_Client3_3 extends Thread{
static final int MAX_THREADS=25;//允许创建的线程的最大数
private static int id=0;//每一个线程的id都不同。
private static int threadCount=0;//当前活动的线程数
private Socket s;
private BufferedReader in;
private PrintWriter out;
public static int getThreadCount(){
return threadCount;
}
public MBP_Client3_3(InetAddress ia) {
threadCount++;
id++;
System.out.println("Making client:"+id);//输出建立线程数
try{
s=new Socket(ia,8888);//创建套接字
}catch(IOException e){}
try{//创建缓冲字符读入器in和字符文本输出流out
in=new BufferedReader(new InputStreamReader(s.getInputStream()));
out=new PrintWriter(new BufferedWriter
(new OutputStreamWriter(s.getOutputStream())),true);
start();//启动
}catch(IOException e1){
try{
s.close();
}catch(IOException e2){}
}
}
public void run(){//线程自动运行
try{
String str;
for(int i=0;i<5;i++){
out.println("Client #"+id+":"+i);//向服务器发送信息
str=in.readLine(); //接收服务器信息
System.out.println("客户端:发送信息#"+id+":"+i+",服务器应答信息:"+str);//显示服务器信息
}
out.println("end");//告知服务器本线程结束
}catch(IOException e){
}finally{
try{
s.close();
}catch(IOException e){}
}
}
public static void main(String[] args)throws IOException,InterruptedException{
InetAddress ia=InetAddress.getByName(null);//参数null代表本地主机
while(true){
if(getThreadCount()<MAX_THREADS)
new MBP_Client3_3(ia); //新建客户端线程
else break; //当前线程数大于MAX_THREADS,退出结束
Thread.currentThread().sleep(100);//当前运行的线程休眠(暂停执行)10毫秒
}
}
}