Java Socket编程入门

Java Socket编程入门

 

        摘要:对Java Socket(套接字)编程做入门的整理、学习的东西太散就老感觉既熟悉又陌生、记录一下、没事的时候可以翻翻看看。以后工作中用到的时候也不会两眼一抹黑、说听过、但是具体说个一二三却哑口无言。注:概念性的解释都是摘抄自网络!

 

一:简介

 

        套接字编程、也是网络编程的基础。网络编程所围绕的核心就是两个或者多个网络上的主机之间信息的传递。所以要实现网络编程就要面临两个问题:

        1、如何准确定位网络上的一台或者多台主机?

        2、当定位成功之后、他们之间如何进行有效可靠的信息传递?

        在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可以唯一地确定Internet上的一台主机。

 

        而TCP层则提供面向应用的可靠(tcp)的或非可靠(UDP)的数据传输机制,这是网络编程的主要对象,一般不需要关心IP层是如何处理数据的。

 

        3、目前较为流行的网络编程模型是客户机/服务器(C/S)结构。即通信双方一方作为服务器等待客户提出请求并予以响应。客户则在需要服务时向服务器提出申请。服务器一般作为守护进程始终运行,监听网络端口,一旦有客户请求,就会启动一个服务进程来响应该客户,同时自己继续监听服务端口,使后来的客户也能及时得到服务。

 

1、TCP/IP 概念

 

        TCP/IP协议(传输控制协议)由网络层的IP协议和传输层的TCP协议组成。IP层负责网络主机的定位,数据传输的路由,由IP地址可以唯一的确定Internet上的一台主机。TCP层负责面向应用的可靠的或非可靠的数据传输机制,这是网络编程的主要对象。


2、TCP、 UDP区别

 

        TCP是一种面向连接的保证可靠传输的协议。通过TCP协议传输,得到的是一个顺序的无差错的数据流。发送方和接收方的成对的两个socket之间必须建立连接,以便在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送或接收操作。

  UDP是一种面向无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。

 

        TCP与UDP区别:

        TCP特点:

  1、TCP是面向连接的协议,通过三次握手建立连接,通讯完成时要拆除连接,由于TCP是面向连接协议,所以只能用于点对点的通讯。而且建立连接也需要消耗时间和开销。

  2、TCP传输数据无大小限制,进行大数据传输。

  3、TCP是一个可靠的协议,它能保证接收方能够完整正确地接收到发送方发送的全部数据。

        UDP特点:

  1、UDP是面向无连接的通讯协议,UDP数据包括目的端口号和源端口号信息,由于通讯不需要连接,所以可以实现广播发送。

  2、UDP传输数据时有大小限制,每个被传输的数据报必须限定在64KB之内。

  3、UDP是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方。

        TCP与UDP应用:

  1、TCP在网络通信上有极强的生命力,例如远程连接(Telnet)和文件传输(FTP)都需要不定长度的数据被可靠地传输。但是可靠的传输是要付出代价的,对数据内容正确性的检验必然占用计算机的处理时间和网络的带宽,因此TCP传输的效率不如UDP高。

  2,UDP操作简单,而且仅需要较少的监护,因此通常用于局域网高可靠性的分散系统中client/server应用程序。例如视频会议系统,并不要求音频视频数据绝对的正确,只要保证连贯性就可以了,这种情况下显然使用UDP会更合理一些。


3、Socket概念

 

        Socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket,一个Socket由一个IP地址和一个端口号唯一确定。应用程序通常通过"套接字"向网络发出请求或者应答网络请求。 Socket是TCP/IP协议的一个十分流行的编程界面,但是,Socket所支持的协议种类也不光TCP/IP一种,因此两者之间是没有必然联系的。在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。

  Socket通讯过程:服务端监听某个端口是否有连接请求,客户端向服务端发送连接请求,服务端收到连接请求向客户端发出接收消息,这样一个连接就建立起来了。客户端和服务端都可以相互发送消息与对方进行通讯。

  Socket的基本工作过程包含以下四个步骤:

  1、创建Socket;

  2、打开连接到Socket的输入输出流;

  3、按照一定的协议对Socket进行读写操作;

  4、关闭Socket。


4、Java Socket

 

        网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket。Socket通常用来实现客户方和服务方的连接。Socket是TCP/IP协议的一个十分流行的编程界面,一个Socket由一个IP地址和一个端口号唯一确定。但是,Socket所支持的协议种类也不光TCP/IP一种,因此两者之间是没有必然联系的。在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。

        Socket通讯的过程

        Server端Listen(监听)某个端口是否有连接请求,Client端向Server 端发出Connect(连接)请求,Server端向Client端发回Accept(接受)消息。一个连接就建立起来了。Server端和Client 端都可以通过Send,Write等方法与对方通信。 

        对于一个功能齐全的Socket,都要包含以下基本结构,其工作过程包含以下四个基本的步骤:

  (1)创建Socket;

  (2)打开连接到Socket的输入/出流;

  (3)按照一定的协议对Socket进行读/写操作;

        (4) 关闭Socket.

 

5、最基本的Server/Client程序

 

        1、Server端

package com.chy.socket.server;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class SingleClientServer {
	private final int port = 7778;
	
	public SingleClientServer() {
		try {
			ServerSocket server = new ServerSocket(port);
			Socket client = server.accept();
			BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));
			System.out.println("client say : " + br.readLine());
			
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
			bw.write("Hello client, this is server...");
			bw.write("\r\n");
			bw.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		new SingleClientServer();
	}
}

2、Client端

package com.chy.socket.client;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import com.chy.socket.utils.ArgumentsUtil;

public class Client_1 {

	public Client_1() {
		try {
			Socket client = new Socket(ArgumentsUtil.host, ArgumentsUtil.port);
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
			bw.write("Hello server, this is " + this.getClass().getName() + " client..." + "\r\n");
			bw.write("\r\n");
			bw.flush();
			
			BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));
			System.out.println(br.readLine() );
			client.close();
			bw.close();
			br.close();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public static void main(String[] args) {
		new Client_1();
	}
}


6、多客户端连接同一服务端

 

        1、Server端

package com.chy.socket.server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import com.chy.socket.thread.ServerThread;
import com.chy.socket.utils.ArgumentsUtil;

public class ManyClientServer {
	private Socket client = null;
	
	public ManyClientServer() {
		try {
			ServerSocket server = new ServerSocket(ArgumentsUtil.port);
			while(true){
				client = server.accept();
				//print the context that is sent by client, and say hello to every client.
				new ServerThread(client).start();
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	public static void main(String[] args) {
		new ManyClientServer();
	}
}

        2、Server端的Thread

package com.chy.socket.thread;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class ServerThread extends Thread {

	private InputStream is = null;
	private OutputStream os = null;
	private Socket client = null;

	public ServerThread(Socket client) {
		try {
			this.is = client.getInputStream();
			this.os = client.getOutputStream();
			this.client = client;
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void run() {
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(is));
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));

			System.out.println(getName() + " say : " + br.readLine());
			
			bw.write("Hello " + Thread.currentThread().getName() + " , this is server..." + "\r\n");
			bw.flush();
			
			client.close();
			br.close();
			bw.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

        3、Client端——Client_2 Client_3 Client_4 基本类似

package com.chy.socket.client;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import com.chy.socket.utils.ArgumentsUtil;

public class Client_2 {
	public Client_2() {
		try {
			Socket client = new Socket(ArgumentsUtil.host, ArgumentsUtil.port);
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
			bw.write("Hello server, this is " + this.getClass().getName() + " client..." + "\r\n");
			bw.flush();
			
			BufferedReader br = new BufferedReader(new InputStreamReader( client.getInputStream()));
			System.out.println(br.readLine());
			
			client.close();
			br.close();
			bw.close();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		new Client_2();
	}
}


         4、Client_3:

package com.chy.socket.client;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import com.chy.socket.utils.ArgumentsUtil;

public class Client_3 {
	
	public Client_3() {
		try {
			Socket client = new Socket(ArgumentsUtil.host, ArgumentsUtil.port);
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
			bw.write("Hello server, this is " + this.getClass().getName() + " client..." + "\r\n");
			bw.flush();
			
			BufferedReader br = new BufferedReader(new InputStreamReader( client.getInputStream()));
			System.out.println(br.readLine());
			
			client.close();
			br.close();
			bw.close();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		new Client_3();
	}
}

7、文件传输

 

        1、Server端:

package com.chy.socket.server;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import com.chy.socket.utils.ArgumentsUtil;
 
/**
 * File upload server.
 */
public class Server extends ServerSocket{
 
     
    private ServerSocket server;
    private Socket client;
    private DataInputStream dis;
    private FileOutputStream fos;
     
    public Server()throws Exception{
        try {
            try {
                server =new ServerSocket(ArgumentsUtil.port);
                 
                while(true){
                    client = server.accept();
                     
                    dis =new DataInputStream(client.getInputStream());
                    //文件名和长度
                    String fileName = dis.readUTF();
                    long fileLength = dis.readLong();
                    fos =new FileOutputStream(new File("d:/" + fileName));
                     
                    byte[] sendBytes =new byte[1024];
                    int transLen =0;
                    System.out.println("----开始接收文件<" + fileName +">,文件大小为<" + fileLength +">----");
                    while(true){
                        int read =0;
                        read = dis.read(sendBytes);
                        if(read == -1)
                            break;
                        transLen += read;
                        System.out.println("接收文件进度" +100 * transLen/fileLength +"%...");
                        fos.write(sendBytes,0, read);
                        fos.flush();
                    }
                    System.out.println("----接收文件<" + fileName +">成功-------");
                    client.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }finally {
                if(dis !=null)
                    dis.close();
                if(fos !=null)
                    fos.close();
                server.close();
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
     
    public static void main(String[] args)throws Exception {
        new Server();
    }
}

        2、Client端:

package com.chy.socket.client;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.net.Socket;

import com.chy.socket.utils.ArgumentsUtil;
 
/**
 * 客户端
 */
public class Client extends Socket{
     
    private Socket client;
    private FileInputStream fis;
    private DataOutputStream dos;
     
    public Client(){
        try {
            try {
                client =new Socket(ArgumentsUtil.host, ArgumentsUtil.port);
                //向服务端传送文件
                File file =new File("c:/test.doc");
                fis =new FileInputStream(file);
                dos =new DataOutputStream(client.getOutputStream());
                 
                //文件名和长度
                dos.writeUTF(file.getName());
                dos.flush();
                dos.writeLong(file.length());
                dos.flush();
                 
                //传输文件
                byte[] sendBytes =new byte[1024];
                int length =0;
                while((length = fis.read(sendBytes,0, sendBytes.length)) >0){
                    dos.write(sendBytes,0, length);
                    dos.flush();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }finally{
                if(fis !=null)
                    fis.close();
                if(dos !=null)
                    dos.close();
                client.close();
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
     
    public static void main(String[] args)throws Exception {
        new Client();
    }
}


补充与总结


1、补充:

上面多次用到的、用于获取IP 和端口号的工具类ArgumentsUtil:

package com.chy.socket.utils;

public class ArgumentsUtil {
	public static int port = 7778;
	public static String host = "127.0.0.1";
}

2、总结:

Java Socket入门很简单、难的是如何处理好在多线程的环境下对各种信息的处理、还有流的正确使用、不会因为对流的工作原理不理解而导致各种各样的奇葩的问题。建议在写多线程的环境下程序的时候、写一点调试一点、如果只顾着闷着头写、到最后出问题再回来调是非常困难的!

Java Socket编程入门,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。