套接字(Socket)是由伯克利大学首创的。它允许程序把网络连接当成一个流,可以向这个流写字节,也可以从这个流读取字节。套接字为程序员屏蔽了网络的底层细节,例如媒体类型、信息包的大小、网络地址、信息的重发等。
Socket是网络上运行的两个程序间双向通信的一端,它既可以接受请求,也可以发送请求,利用它可以较为方便地编写网络上数据的传递。在Java中,有专门的Socket类处理用户的请求和响应。利用Socket类的方法,就可以实现两台计算机之间的通信。
套接字能执行7种基本操作:
连接到远程机器。
绑定到端口。
接收从远程机器来的绑定端口上的连接。
监听到达的数据。
发送数据。
接收数据。
关闭连接。
java.net.Socket类是Java的基础类,用于执行客户端的TCP操作。套接字有两种:一种套接字在服务器端创建,叫做服务器套接字(ServerSocket);还有一种在客户端被创建,就是客户端套接字。
1 客户端套接字
1.1 构造函数
1.public Socket(String host ,int port) throws unknownHostException IOException
这个方法建立一个到主机host、端口号为port的套接字,连接到远程主机。
示范代码如下:
try {
Socket soc=new Socket ("www.sdfd.net" , 80);
//发送数据
}
catch(unknownHostException uex) {
}
catch(IOException e) {
}
2.public Socket (InetAddress host ,int port ) throws IOException
建立一个套接字,与前一个不同的是它用InetAddress对象指定套接字。如果出错则抛出IOException异常。
1.2 常用的方法
1.public InetAddress getInetAddress ( )
调用Socket对象的getInetAddress ( )方法返回连接到远程主机的地址,如果连接失败,则返回以前连接的主机。实例如下:
try {
Socket socket = new Socket ("www.snm.com" ,80);
InetAddress host =socket.getInetAddress ( );
//操作
}
catch( IOException e) {
//异常处理
}
catch (unknownHostException e) {
//异常处理
}
2.public int getPort ( )
返回Socket连接到远程主机的端口号。示范代码如下:
try {
Socket socket =new Socket ("www.snm.com",80);
int port =socket.getPort ( );
//操作
}
catch( IOException e) {
//异常处理
}
catch (unknownHostException e) {
//异常处理
}
3.public int getLocalPort ( )
一个Socket连接两个终端,方法getLocalPort( )返回本地连接终端的端口号。示范代码如下:
try {
Socket socket =new Socket ("www.snm.com" ,80);
int port =socket.getLocalPort ( );
//操作
}
catch( IOException e) {
//异常处理
}
catch (unknownHostException e) {
//异常处理
}
4.public InetAddress getLocalAddress ( )
此方法告诉用户套接字绑定到哪个网络接口。用户通常在多目录的主机或带有多目录的网络接口上使用这个方法。
5.public InputStream getInputStream( ) throws IOException
这个方法返回一个输入流,利用这个流就可以从套接字读取数据。通常链接这个流到一个BufferedInputStream或者BufferedReader。
6.public OutputStream getOutputStream ( ) throws IOException
返回一个原始的OutputStream,可以从应用程序写数据到套接字的另一端。通常将它链接到DataOutputStream或者OutputStreamWriter等更方便的类,还可以利用缓冲。示范代码如下:
OutputStreamWriter out;
try {
Socket socket = new Socket ("www.sdhn.net",80 );
OutputStream outs=socket.getOutputStream ( );
BufferedOutputStream buffer=new BufferedOutputStream(outs);
out =new OutputStreamWriter (buffer , "ASCII");
out.write("the java networking");
}
catch (Exception e) {
}
finally
{
try {
out.close( );
}
catch (Exceptin e) {
}
}
7.public synchronized void close( ) throws IOException
虽然套接字会在两个数据流之一被关闭、程序结束时会被自动地关闭,但是我们应该用close()方法断开连接,特别是要运行无限长时间的程序时。关闭套接字的示范代码如下:
Socket socket=null;
try {
socket=new Socket("www.sdhj.com",80 );
//套接字操作
}
catch( IOException e) {
//异常处理
}
catch (unknownHostException e) {
//异常处理
}
finally {
if (socket!=null)
socket.close ( );
}
2 服务器套接字
每个服务器套接字运行在服务器上特定的端口,监听在这个端口的TCP连接。当远程客户端的Socket试图与服务器指定端口建立连接时,服务器被激活,判定客户程序的连接,并打开两个主机之间固有的连接。一旦客户端与服务器建立了连接,则两者之间就可以传送数据,而数据是通过这个固有的套接字传递的。
在ServerSocket类中包含了创建ServerSocket对象的构造方法、在指定端口监听的方法、建立连接后发送和接收数据的方法。
ServerSocket的工作过程如下:
(1)用ServerSocket()方法在指定端口创建一个新的ServerSocket对象。
(2)ServerSocket对象调用accept( )方法在指定的端口监听到来的连接。accept( )一直处于阻塞状态,直到有客户端试图建立连接。这时accept( )方法返回连接客户端与服务器的Socket对象。
(3)调用getInputStream( )方法或者getOutputStream( )方法或者两者全调用建立与客户端交互的输入流和输出流。具体情况要看服务器的类型而定。
(4)服务器与客户端根据一定的协议交互,直到关闭连接。
(5)服务器、客户机或者两者都关闭连接。
(6)服务器回到第2步,继续监听下一次的连接。
下面我们介绍一下与客户端套接字不同的服务器套接字的方法。
构造方法如下:
public ServerSocket(int port ) throws IOException BindException
public ServerSocket(int port ,int queuelength) throws IOException BindException
public ServerSocket(int port ,int queuelength,InetAddress bindaddress) throws
IOException,BindException
这些构造方法允许指定端口,用来保存到来连接请求队列的长度,绑定本地网络的地址。如果想在端口5300创建一个服务器端口,同时使队列中所能存储的到来的请求数为100,则示范代码如下:
try {
ServerSocket socket=new ServerSocket(5300 ,100);
}
catch(IOException e) {
//异常处理
}
常用方法如下:
public Socket accept ( ) throws IOException
服务器建立并准备接收连接时,调用ServerSocket的 accept( )方法。这个方法是阻塞的:它停止执行流等待下一个客户端的连接。当客户端请求连接时,accept( )方法返回一个Socket对象。然后就用这个Socket对象的getInputStream( )和getOutputStream( )方法返回的流与客户端交互。示范代码如下:
ServerSocket server=new ServerSocket( );
While (true)
{
Socket connection =server.accept ( );
OutputStream out=new OutputStream (connection.getOutputStream( ));
out.write("the java networking" );
connection.close( );
}
public void close ( ) throws IOException 实现了服务器套接字后要关闭它。
public InetAddress getInetAddress( )
public int getLocalPort ( )
3 实例:C/S环境下的套接字应用程序
下面我们介绍客户/服务器环境下的套接字应用程序。
客户/服务器在分布处理过程中,使用基于连接的网络通信模式。该通信模式首先在客户机和服务器之间定义一套通信协议,并创建一个 Socket类,利用这个类建立一条可靠的连接;然后,客户/服务器再在这条连接上可靠地传输数据。客户机发出请求,服务器监听来自客户机的请求,并为客户机提供响应服务。这就是典型的"请求-应答"模式。下面是客户/服务器的一个典型运作过程:
(1)服务器监听相应端口的输入。
(2)客户机发出一个请求。
(3)服务器接收到此请求。
(4)服务器处理这个请求,并把结果返回给客户机。
(5)重复上述过程,直至完成一次会话过程。
按照以上过程,我们使用Java语言编写一个分别针对服务器和客户机的应用程序(Application)。服务器程序负责监听客户机请求,为每个客户机请求建立Socket连接,从而为客户机提供服务。本程序提供的服务为:读取来自客户机的命令,根据客户机的命令,决定服务器要发给客户机的信息,并发送给客户机,见示例12-5。
【程序源代码】
1 // ==================== Program Description ========================
2 // 程序名称:示例12-5: KKMultiServerThread.java
3 // 程序目的:创建server端线程类
4 //=============================================================
5 import java.net.*;
6 import java.io.*;
7
8 public class KKMultiServerThread extends Thread
9 {
10 private Socket socket = null;
11
12 public KKMultiServerThread(Socket socket) {
13 super("KKMultiServerThread");
14 this.socket = socket;
15 }
16
17 public void run()
18 {
19 try {
20 PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
21 BufferedReader in = new BufferedReader( new InputStreamReader(
22 socket.getInputStream()));
23 String inputLine, outputLine;
24 KnockKnockProtocol kkp = new KnockKnockProtocol();
25 outputLine = kkp.processInput(null);
26 out.println(outputLine);
27
28 while ((inputLine = in.readLine()) != null)
29 {
30 outputLine = kkp.processInput(inputLine);
31 out.println(outputLine);
32 if (outputLine.equals("Bye"))
33 break;
34 }
35 out.close();
36 in.close();
37 socket.close();
38 } catch (IOException e) {
39 e.printStackTrace();
40 }
41 }
42 }
【程序注解】
类KKMultiServerThread继承自线程类,有一个Socket成员变量socket,在构造函数中初始化了socket变量。下面看看如何实现线程的run()方法。
首先定义了PrintWriter out和BufferedReader in,使输入输出流与socket相关联。然后声明了KnockKnockProtocol对象 kkp,读取客户端的命令,根据kkp中定义的协议,决定要发送给客户的信息,并发送出去。最后调用out.close()、in.close()和 socket.close()关闭输入输出流和套接字。
示例12-6是多线程服务器程序。
【程序源代码】
1 // ==================== Program Description =====================
2 // 程序名称:示例12-6: KKMultiServer.java
3 // 程序目的:多线程服务器
4 //=========================================================
5 import java.net.*;
6 import java.io.*;
7
8 public class KKMultiServer
9 {
10 public static void main(String[] args) throws IOException
11 {
12 ServerSocket serverSocket = null;
13 boolean listening = true;
14
15 try {
16 serverSocket = new ServerSocket(4444);
17 } catch (IOException e) {
18 System.err.println("Could not listen on port: 4444.");
19 System.exit(-1);
20 }
21
22 while (listening)
23 new KKMultiServerThread(serverSocket.accept()).start();
24
25 serverSocket.close();
26 }
27 }
【程序注解】
第12行声明了一个ServerSocket对象serverSocket。第16行实例化了 serverSocket,监听端口为4444。然后就是监听客户端的连接(使用serverSocket.accept()方法)。如果有客户端的连接,则serverSocket.accept()就返回一个Socket套接字,以这个套接字实例化一个KKMultiServerThread对象,实际处理客户端的数据。
下面的程序示例12-7实现了服务器端与客户端交互的协议。
【程序源代码】
1 // ==================== Program Description =====================
2 // 程序名称:示例12-7: KnockKnockProtocol.java
3 // 程序目的:服务端与客户端相互交互的协议
4 //=============================================================
5 import java.net.*;
6 import java.io.*;
7
8 public class KnockKnockProtocol
9 {
10 private static final int WAITING = 0;
11 private static final int SENTKNOCKKNOCK = 1;
12 private static final int SENTCLUE = 2;
13 private static final int ANOTHER = 3;
14
15 private static final int NUMJOKES = 5;
16
17 private int state = WAITING;
18 private int currentJoke = 0;
19
20 private String[] clues = { "Turnip", "Little Old Lady",
"Atch", "Who", "Who" };
21 private String[] answers = { "Turnip the heat, it's cold in here!",
22 "I didn't know you could yodel!",
23 "Bless you!",
24 "Is there an owl in here?",
25 "Is there an echo in here?" };
26
27 public String processInput(String theInput)
28 {
29 String theOutput = null;
30
31 if (state == WAITING) {
32 theOutput = "Knock! Knock!";
33 state = SENTKNOCKKNOCK;
34 }
35 else if (state == SENTKNOCKKNOCK) {
36 if (theInput.equalsIgnoreCase("Who's there?")) {
37 theOutput = clues[currentJoke];
38 state = SENTCLUE;
39 }
40 else {
41 theOutput = "You're supposed to say "Who's there?"! " +
42 "Try again. Knock! Knock!";
43 }
44 }
45 else if (state == SENTCLUE) {
46 if (theInput.equalsIgnoreCase(clues[currentJoke] + " who?")) {
47 theOutput = answers[currentJoke] + " Want another? (y/n)";
48 state = ANOTHER;
49 } else {
50 theOutput = "You're supposed to say "" +
clues[currentJoke] + " who?"" +
51 "! Try again. Knock! Knock!";
52 state = SENTKNOCKKNOCK;
53 }
54 }
55 else if (state == ANOTHER) {
56 if (theInput.equalsIgnoreCase("y")) {
57 theOutput = "Knock! Knock!";
58 if (currentJoke == (NUMJOKES - 1))
59 currentJoke = 0;
60 else
61 currentJoke++;
62 state = SENTKNOCKKNOCK;
63 }
64 else {
65 theOutput = "Bye.";
66 state = WAITING;
67 }
68 }
69 return theOutput;
70 }
71 }
【程序注解】
KnockKnockProtocol类具体定义了客户端与服务器交互的协议。定义了两个字符串数组clues = { "Turnip", "Little Old Lady", "Atch", "Who", "Who" }; answers = { "Turnip the heat, it's cold in here!", "I didn't know you could yodel!", "Bless you!", "Is there an owl in here?", "Is there an echo in here?" }。在processInput(String theInput)方法中根据这两个字符串和客户端的命令String theInput 决定要发送给客户端的字符串。程序假定了客户端应该发送的字符串,如果发现接收的字符串不符合,则返回提醒的字符串,交由socket发送给客户端。
示例12-8是客户端源程序。
【程序源代码】
1 // ==================== Program Description =====================
2 // 程序名称:示例12-8: KnockKnockClient.java
3 // 程序目的:客户端源程序
4 //=========================================================
5 import java.io.*;
6 import java.net.*;
7
8 public class KnockKnockClient
9 {
10 public static void main(String[] args) throws IOException
11 {
12 Socket kkSocket = null;
13 PrintWriter out = null;
14 BufferedReader in = null;
15
16 try {
17 kkSocket = new Socket("hostname", 4444);
18 out = new PrintWriter(kkSocket.getOutputStream(), true);
19 in = new BufferedReader(new
InputStreamReader(kkSocket.getInputStream()));
20 }
21 catch (UnknownHostException e) {
22 System.err.println("Don't know about host: taranis.");
23 System.exit(1);
24 }
25 catch (IOException e) {
26 System.err.println("Couldn't get I/O for the
connection to: biao.");
27 System.exit(1);
28 }
29
30 BufferedReader stdIn = new BufferedReader(new
InputStreamReader(System.in));
31 String fromServer;
32 String fromUser;
33
34 while ((fromServer = in.readLine()) != null)
35 {
36 System.out.println("Server: " + fromServer);
37 if (fromServer.equals("Bye."))
38 break;
39
40 fromUser = stdIn.readLine();
41 if (fromUser != null) {
42 System.out.println("Client: " + fromUser);
43 out.println(fromUser);
44 }
45 }
46
47 out.close();
48 in.close();
49 stdIn.close();
50 kkSocket.close();
51 }
52 }
【程序输出结果】如下所示。
Server: Knock! Knock!
Who's there?
Client: Who's there?
Server: Turnip
Turnip who?
Client: Turnip who?
Server: Turnip the heat, it's cold in here! Want another? (y/n)
【程序注解】
在客户端程序中,第17行建立了一个套接字与服务器保持联系,然后用一个PrintWriter和一个BufferedReader与套接字相关联,以便能更好地与服务器相交互。而BufferedReader stdIn与客户端的标准输入System.in相关联。在while循环中,处理从服务器读取的数据,并把从stdIn中读取的数据发给服务器。最后调用out.close() 、in.close()、stdIn.close() 和kkSocket. close( )关闭套接字和输入输出流。
客户端假定按先后顺序输入为"who's there ?"和"Turnip who?",如果你不是这样输入的话,服务器端不认识你输入的命令,会提示你该输入的命令。
分享到:
相关推荐
基于VS2015的客户端/服务器例程 适合初学者学习套接字的例程 封装完整,思路条理
windows套接字使用的例子程序 客户端和服务器端 VS2008工程
提供了一个用 MATLAB 编写的示例服务器/客户端,它利用调用 Java 内联的能力来使用 TCP/IP 执行消息通信。 重要的是,它不需要任何预编译的 DLL 或强制您编译一些 MEX c 文件。 它也不需要任何额外的工具箱它都包含...
这部分主要使用的模块就是 socket 模块,在这个模块中可以找到 socket()函数,该函数用于创建套接字对象,套接字也有自己的方法集,这些方法可以实现基于套接字的网络通信。 socket()模块函数 要创建套接字,必须...
利用Socket (套接字)开发的客户端,可以与服务器通讯传输文件和字符。
此类库可以直接套用,在C#中。调用类库内方法‘SocketClientclient’就可以
提供了一个用 MATLAB 编写的示例服务器/客户端,它利用调用 Java 的能力使用 TCP/IP 执行消息通信。 与我之前的示例 ( http://www.mathworks.com/matlabcentral/fileexchange/21131 ) 类似,但通过使用帮助程序 ...
《TCP/IP网络编程》针对网络编程初学者,面向具备C语言基础的套接字网络编程学习者,适合所有希望学习Linux和Windows网络编程的人。 第一部分 开始网络编程 第1章 理解网络编程和套接字 2 1.1 理解网络编程...
网络编程的本质是两个设备之间的数据交换,当然,在计算机网络中,设备主要指计算机。数据传递本身没有多大的难度,不就是把一个设备中的数据发送给另外一个设备,然后接受另外一个设备反馈的数据。...
一个自己的小程序,适合初学者学习TCP/IP与Socket套接字的使用
Debug较大,不得于上传,已删。下载的朋友可自行运行得到exe文件。 系统是实现一个有图形...C++语言有SOCKET套接字,基于TCP/IP的通信基本上都是利用SOCKET套接字进行数据通讯,程序一般分为服务器端和客户端两部分。
套接字的创建,其实有了解过udp的人应该知道这两者在一些方面还是差不多的,你需要创建一个socket()对象 并且这是客户端和服务端都需要的第一步。 第二 服务端需要去绑定本机IP和端口(bind()) 第三 listen监听模式,...
接受客户端连接:使用 accept 函数接受客户端的连接请求,并创建一个新的套接字用于与客户端进行通信。 从客户端接收数据:使用 read 函数从客户端接收数据。 向客户端发送消息:使用 send 函数向客户端发送消息。 ...
TCP聊天文件服务器v2.2 - 服务端客户端套接字解决分包/粘包问题 - SocketQueue继承以及减少冗余 包括py文件, ui, 以及杂七杂八的东西...
研究生(TCP/IP网络互连技术)上课课件,主要讲windows套接字C++网络编程,客户端—服务器编程与应用。课件主要以程序为主,而且有许多完整的案例,对网络编程学习者一定大有帮助!
利用属性页和套接字类,实现客户端和服务器端,方便二者通信
2 实验内容 基于TCP/IP的通信基本上都是利用SOCKET套接字进行数据通讯,程序一般分为服务器端和用户端两部分。设计思路(VC6.0下): 第一部分 服务器端 一、创建服务器套接字(create)。 二、服务器套接字进行...
实现基于TCP套接字的简单的服务器与客户端通信实验报告5页.pdf
2.5 技巧5:套接字接口比XTI/TLI更好用 41 2.6 技巧6:记住,TCP是一种流协议 43 2.7 技巧7:不要低估TCP的性能 50 2.7.1 UDP源程序与接收程序 52 2.7.2 TCP源程序及接收程序 53 2.7.3 小结 59 2.8 技巧8:...
atlSocket.dll 和配套的 M 函数可以通过 TCP/IP 套接字创建、打开、关闭、发送和接收数据。 DLL 是一个 ActiveX DLL 并实现了套接字的客户端。 只能发送和接收向量(一维矩阵)。 MATLAB 的基本双精度数据类型可以...