JavaSE——TCP协议网络编程(一)

实现客户端与服务端的连接: 

  1. 创建TCP服务端的 ServerSocket

  ServerSocket :此类实现服务器套接字。服务器套接字请求通过网络传入,基于该请求执行某些操作,然后可能向请求者返回结果。

  其 accept()方法接受来自客户端的连接请求,并返回一个用于与Client 通信的Socket 对象。此后Server 的对象server 只要向该Socket 对象读写数据,就可以向远程的Client 读写数据。

下面是一个典型的创建Server端ServerSocket的过程。
  ServerSocket server=null;
  try {
     server=new ServerSocket(4700);
     //创建一个ServerSocket在端口4700监听客户请求
  }catch(IOException e){
     System.out.println("can not listen to :"+e);
  }
  Socket socket=null;
  try {
    socket=server.accept();
    //accept()是一个阻塞的方法,一旦有客户请求,它就会返回一个Socket对象用于同客户进行交互
  }catch(IOException e){
    System.out.println("Error:"+e);
  }

  以上的程序是Server的典型工作模式,只不过在这里Server只能接收一个请求,接受完后Server就退出了。实际的应用中总是让它不停的循环接收,一旦有客户请求,Server总是会创建一个服务线程来服务新来的客户,而自己继续监听。程序中accept()是一个阻塞函数,所谓阻塞性方法就是说该方法被调用后,将等待客户的请求,直到有一个客户启动并请求连接到相同的端口,然后accept()返回一个对应于客户的socket。这时,客户方和服务方都建立了用于通信的socket,接下来就是由各个socket分别打开各自的输入/输出流。

  

  ServerSocket 类的构造方法:

ServerSocket()
          创建非绑定服务器套接字。
ServerSocket(int port)
          创建绑定到特定端口的服务器套接字。
ServerSocket(int port, int backlog)
          利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。
ServerSocket(int port, int backlog, InetAddress bindAddr)
          使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。

  ServerSocket 类的常用方法

 Socket accept()
          侦听并接受到此套接字的连接。
 void bind(SocketAddress endpoint, int backlog)
          将 ServerSocket 绑定到特定地址(IP 地址和端口号)。
 void close()
          关闭此套接字。
 InetAddress getInetAddress()
          返回此服务器套接字的本地地址。
 boolean isBound()
          返回 ServerSocket 的绑定状态。
 boolean isClosed()
          返回 ServerSocket 的关闭状态。

简要代码:

ServerSocket server = new ServerSocket( 有效端口号 );

Server client = server.accept(); // 在没有接收到客户端连接请求时, accept 属于堵塞状态,接收到后继续                                                        //运行。

if(client!=null){

  System.out.println("有客户端连接上来了");

}

 2.TCP客户端的Socket

  Socket 类:此类实现客户端套接字(“套接字”)套接字是两台机器间通信的端点。用于将应用程序和端口连接起来。不同的端口确定连接到服务器的哪项服务上。

  创建一个Socket类之后,通过调用 Socket 的getInputStream 方法从服务程序获得输入流传送来的消息;通过调用 getOutputStream 方法获得输出流来发送消息。

      创建 Socket:

      下面是一个典型的创建客户端Socket的过程。
   try{
     Socket socket=new Socket("127.0.0.1",4700);
     //127.0.0.1是TCP/IP协议中默认的本机地址
   }catch(IOException e){
     System.out.println("Error:"+e);
   }

  这是最简单的在客户端创建一个Socket的一个小程序段,也是使用Socket进行网络通讯的第一步,程序相当简单,在这里不作过多解释了。在后面的程序中会用到该小程序段。

     
  注意,在选择端口时,必须小心。每一个端口提供一种特定的服务,只有给出正确的端口,才能获得相应的服务。0~1023的端口号为系统所保留,例如http服务的端口号为80,telnet服务的端口号为21,ftp服务的端口号为23, 所以我们在选择端口号时,最好选择一个大于1023的数以防止发生冲突。

  在创建socket时如果发生错误,将产生IOException,在程序中必须对之作出处理。所以在创建Socket或ServerSocket是必须捕获或抛出例外。

  常用的构造方法:

  Socket()
          通过系统默认类型的 SocketImpl 创建未连接套接字
  Socket(InetAddress address, int port)
          创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
  Socket(InetAddress address, int port, InetAddress localAddr, int localPort)
          创建一个套接字并将其连接到指定远程地址上的指定远程端口。
protected Socket(SocketImpl impl)
          使用用户指定的 SocketImpl 创建一个未连接 Socket。
  Socket(String host, int port)
          创建一个流套接字并将其连接到指定主机上的指定端口号。
  Socket(String host, int port, InetAddress localAddr, int localPort)
          创建一个套接字并将其连接到指定远程主机上的指定远程端口。

       其中address、host和port分别是双向连接中另一方的IP地址、主机名和端口号,stream指明socket是流socket还是数据报socket,localPort表示本地主机的端口号,localAddr和bindAddr是本地机器的地址(ServerSocket的主机地址),impl是socket的父类,既可以用来创建serverSocket又可以用来创Socket。count则表示服务端所能支持的最大连接数。例如:
  Socket client = new Socket("127.0.01.", 80);
  ServerSocket server = new ServerSocket(80);

常用的方法:

 void bind(SocketAddress bindpoint)
          将套接字绑定到本地地址。
 void close()
          关闭此套接字。
 void connect(SocketAddress endpoint)
          将此套接字连接到服务器。
 void connect(SocketAddress endpoint, int timeout)
          将此套接字连接到服务器,并指定一个超时值。
 InetAddress getInetAddress()
          返回套接字连接的地址。
 InputStream getInputStream()
          返回此套接字的输入流。
 InetAddress getLocalAddress()
          获取套接字绑定的本地地址。
 OutputStream getOutputStream()
          返回此套接字的输出流。
 SocketAddress getRemoteSocketAddress()
          返回此套接字连接的端点的地址,如果未连接则返回 null
 boolean isBound()
          返回套接字的绑定状态。
 boolean isClosed()
          返回套接字的关闭状态。
 boolean isConnected()
          返回套接字的连接状态。
 boolean isInputShutdown()
          返回是否关闭套接字连接的半读状态 (read-half)。
 boolean isOutputShutdown()
          返回是否关闭套接字连接的半写状态 (write-half)。
 void shutdownInput()
          此套接字的输入流置于“流的末尾”。
 void shutdownOutput()
          禁用此套接字的输出流。
 String toString()
          将此套接字转换为 String

 简要代码:

Socket client = new Socket("127.0.0.0",9999);  服务端IP地址与端口号。

  查询计算机的ip地址和端口号:

  打开命令提示符,输入:
  ipconfig/all   (windows ip configuration 视窗操作系统ip配置)查看当前IP及电脑网络配置; 显示当前电脑ip相关所有信息,包括ip地址、网卡(mac)地址。
  netstat -an ,查看当前所有连接端口; netstat(在内核中访问网络及相关信息的程序)显示网络连接、路由表和网络接口信息,可以让用户得知目前都有哪些网络连接正在运作。

package 网络编程;

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

public class Server{
    public static void main(String[] args) {
        try {
            
            ServerSocket server = new ServerSocket(9657);
            Socket client = server.accept();
            if(client!=null){
                System.out.println("有客户端连接上来了");
                server.close();
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
package 网络编程;

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

public class Client {


    public static void main(String[] args) {
    
            
                try {
                    Socket client = new Socket("127.0.0.1",9657);
                    client.close();
                } catch (UnknownHostException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
    }

}

output:有客户端连接上来了。

此段服务端代码存在问题,客户端与服务端建立连接之后服务会自动关闭,不能继续接受多个客户端的请求。可以加上一个 while 循环,使服务端接受一个客户端的请求后又回到 accept() 的接受状态。

3.ServerSocket 类与Socket 类的不同用法:

ServerSocket类:

创建一个ServerSocket类,同时在运行该语句的计算机的指定端口处建立一个监听服务,如:
    ServerSocket MyListener = new ServerSocket(600);
    这里指定提供监听服务的端口是600,一台计算机可以同时提供多个服务,这些不同的服务之间通过端口号来区别,不同的端口号上提供不同的服务。为了随时监听可能的Client请求,执行如下的语句:
    Socket LinkSocket = MyListener.accept();
    该语句调用了ServerSocket对象的accept()方法,这个方法的执行将使Server端的程序处于等待状态,程序将一直阻塞直到捕捉到一个来自Client端的请求,并返回一个用于与该Client通信的Socket对象Link-Socket。此后Server程序只要向这个Socket对象读写数据,就可以实现向远端的Client读写数据。结束监听时,关闭ServerSocket对象:
    Mylistener.close();

Socket 类:

当Client程序需要从Server端获取信息及其他服务时,应创建一个Socket对象:
    Socket socket=new Socket(“ServerComputerName”,600);
    Socket类的构造函数有两个参数,第一个参数是欲连接到的Server计算机的主机地址,第二个参数是该Server机上提供服务的端口号。
    Socket对象建立成功之后,就可以在Client和Server之间建立一个连接,并通过这个连接在两个端点之间传递数据。利用Socket类的方法getOutputStream()和getInputStream()分别获得向Socket读写数据的输入/输出流,最后将从Server端读取的数据重新返还到Server端。
    当Server和Client端的通信结束时,可以调用Socket类的close()方法关闭Socket,拆除连接。

ServerSocket 一般仅用于设置端口号和监听,真正进行通信的是服务器端的Socket与客户端的Socket,在ServerSocket 进行accept之后,就将主动权转让了。    

原文地址:https://www.cnblogs.com/linlin0/p/6194678.html