实现客户端与服务端的连接:
- 创建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之后,就将主动权转让了。