本节讲点:

  • 客户端套接字:Socket:Socket的创建和使用方法,以及Socket选项和异常。

  • 服务端套接字:ServerSocket:SeverSocket的创建和使用方法,以及ServerSocket选项

  • 简单的Client/Server对话程序

  • 支持多客户端的Client/Server服务响应程序


在学习JDK的网络编程之前先要了解一下网络基础知识和网络协议。

TCP(传输控制协议)一种基于连接的通信协议。可靠传输

UDP(用户数据包协议)不稳定连接的通信协议

TCP和UDP的端口如下:

Telnet:23

SMTP(简单邮件传输协议):25

HTTP(超文本传输协议):80

POP3:110


IP地址类InetAddress

Socket编程意在建立服务器端IP和客户端IP的网络通信连接,因此IP的寻址是建立连接的基础。InetAddress类是Java的IP地址封装类,表示互联网协议地址。IP地址是IP使用的32位或128位无符号数字,它是低级协议,TCP和UDP协议都是在它的基础上构建的。InetAddress类提供了如下操作:

  1. 创建InetAddress对象的方法。

    InetAddress类没有构造方法,要创建该类的实例对象,可以通过该类的静态方法获得该对象。

    (1)取得本机地址:getLocalHost()

函数定义:public static InetAddress getLocalHost() throws UnkonwnHostException;
示例:
try{
    //取得本机地址
    InetAddress local = InetAddress.getLocalhost();
    System.out.println(local);
}catch(UnkownHostException e){}

    (2)根据主机名获取地址:getByName(String host);

    (3)根据主机名取得一组地址:getAllByName(String host);

    (4)根据IP取得地址:getByAddress(byte[] addr);

            IPv4地址中,使用4个字节表示,IPv6中使用6个字节表示

    (5)根据主机名和IP取得地址:getByAddress(String host,byte[] addr)

2、取得InetAddress类的属性

    获取此IP地址的完全限定域名

    String getCanonicalHostName();

    返回IP地址字符串

    String getHostAddress();

    获取此IP地址的主机名

    String getHostName();

3、判断地址的版本是IPv4还是IPv6

try{
    //取得本机地址
    InetAddress local = InetAddress.getLocalHost();
    //IPv4  or IPv6
    byte[] addr = local.getAddress();
    if(addr.length == 4){
        System.out.println("IP版本 is IPv4");
        int firstByte = addr[0];
        if(firstByte < 0){
            firstByte += 256;
        }
        if((firstByte & 0x80) == 0){
            System.out.println("IP类别 is A");
        }else if((firstByte & 0xC0) == 0){
            System.out.println("IP类别 is B");
        }else if((firstByte & 0xE0) == 0){
            System.out.println("IP类别 is C");
        }else if((firstByte & 0xF0) == 0){
            System.out.println("IP类别 is D");
        }else if((firstByte & 0xF8) == 0){
            System.out.println("IP类别 is E");
        }
    }else if(addr.length == 6){
        System.out.pringln("IP 版本 is IPv6");
    }
}catch(UnkownHostExcetion e){
    e.printStackTrace();
}


4、客户端套接字Socket

    套接字(Socket)允许程序把网络连接当成一个流,可以向这个流写字节,也可以从这个流中读取字节。套接字为程序员屏蔽了网络的底层细节。

    Socket是网络上运行的两个程序间双向通信的一段,它可以接受请求,也可以发送请求,利用它较为方便地编写网络上数据的传递。

    Socket的工作过程如下:

    (1)、连接到远程机器

    (2)、绑定到端口

    (3)、接收从远程机器来的绑定端口的连接

    (4)、监听到达的数据

    (5)、发送数据

    (6)、接收数据

    (7)、关闭连接

    

    1、创建套接字对象

  • 建立一个到主机host、端口号为port的套接字,连接到远程主机,方法如下:

public Socket(String host,int port) throws unkownHostException IOException;

示例如下:
try{
    Socket socket = new Socket("www.baidu.om",80);
}catch(unkownHostException uex){
}catch(IOException e){
}
  • 建立一个套接字,与前一个不同的是它用InetAddress对象指定套接字,如果出错则抛出IOException

public Socket(InetAddress host,int port) throws IOException;

示例如下:
try{
    InetAddress addr = InetAddress.getByName("www.baidu.com");
    Socket socket = new Socket(addr,80);
}catch...


5、服务器端套接字ServerSocket

    每个服务器套接字运行在服务器上有特定的端口,监听这个端口的TCP连接。当远程客户端的Socket试图与服务器指定端口连接时,服务器被激活,判断客户端的连接,并打开两个主机之间固有的连接。一旦客户端与服务器建立了连接,则两者之间就可以传送数据,而数据时通过这个固有的套接字传递的。

    ServerSocket的工作过程如下:

    (1)、用ServerSocket()方法在指定端口创建一个新的ServerSocket对象

    (2)、ServerSocket对象调用accept()方法在指定端口监听到来的连接。accept()一直处于阻塞状态,知道有客户端试图建立连接,这时accept()方法返回连接客户端与服务器的Socket对象

    (3)、调用getInputStream()方法或者getOutputStream()方法,或者两者全调用,建立与客户端交互的输入流或输出流。

    (4)、服务器与客户端根据一定的协议交互,知道关闭连接

    (5)、服务器、客户端或者两者都关闭连接。

    (6)、服务器回到第2步,继续监听下一个连接

    1、创建SeverSocket对象

        创建绑定到特定端口的服务器套接字

         ServerSocket(int port);

try{
    SeverSocket server = new ServerSocket(12345);
}catch(IOException e){

}

        利用指定的backlog创建服务器套接字,并将其绑定到指定的本地端口。backlog表示传入连接指示(对连接的请求)的最大队列长度,如果队列满时受到连接提示,则拒绝连接。backlog参数必须是大于0的正值,如果传递的值小于或者等于0,则使用默认值。

        ServerSocket(int port,int backlog);

try{
    SeverSocket server = new ServerSocket(12345,20);
}catch(IOException e){

}

服务器端示例如下:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @author Administrator
 * Java socket 服务器端简单示例
 */
public class OneServer {

	public static void main(String[] args) {
		// 启动服务器端
		ServerSocket server = null;
		try {
			server = new ServerSocket(12345);
			System.out.println("服务器启动"+
					server.getInetAddress().getHostAddress()+":"+
					server.getLocalPort());
			while(true){
				//监听客户端
				Socket socket = server.accept();
				System.out.println("客户端连接"+
						socket.getInetAddress().getHostAddress()+":"+
						socket.getPort());
				//输入输出流
				BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
				
				BufferedReader is = new BufferedReader(new InputStreamReader(socket.getInputStream()));
				PrintWriter os = new PrintWriter(socket.getOutputStream());
				
				//循环处理客户端输入
				String line;
				while((line = is.readLine()) != null){
					System.out.println("收到客户端:"+line);
					if(line.equals("bye")){
						System.out.println("拜拜,我上天去了");
						break;
					}else{
						//读取键盘输入并回复客户端
						os.println(sin.readLine());
						os.flush();
					}
				}
				//关闭输入/输出流
				is.close();
				os.close();
				
				//关闭客户端
				socket.close();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				server.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}

}

客户端示例:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

public class OneClient {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		try {
			//连接服务器
			Socket socket = new Socket(InetAddress.getLocalHost(),12345);
			//输入输出流
			
			BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
			
			BufferedReader is = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			PrintWriter os = new PrintWriter(socket.getOutputStream());
			//循环读入键盘输入内容
			String readLine;
			while((readLine = sin.readLine()) != null){
				os.println(readLine);
				os.flush();
				//读取服务器端回复
				String responeLine = is.readLine();
				System.out.println("服务器端回复:"+responeLine);
			}
			//关闭输出流
			is.close();
			os.close();
			
			//关闭客户端
			socket.close();
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

运行结果

wKioL1c-wqGyjsCfAACYrSnKzz0480.png