套接字(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?",如果你不是这样输入的话,服务器端不认识你输入的命令,会提示你该输入的命令。
分享到:
相关推荐
通过阅读和分析这些代码,我们可以学习到如何使用系统提供的socket库函数来创建、连接、读写TCP套接字,以及如何处理并发连接和错误处理。 源代码的学习可以帮助我们理解以下关键概念: 1. socket()函数:创建套接...
总的来说,TCP/IP服务器客户端通讯源代码的实现涉及网络编程、VC++编程和Winsock API的使用。通过学习和实践这些示例代码,你可以深入理解网络通信的底层机制,并具备开发自己TCP/IP应用的能力。
- 接受连接:`accept()`函数接收客户端的连接请求,返回一个新的套接字用于与客户端通信。 - 读写数据:使用`read()`和`write()`函数进行数据的发送和接收。 - 关闭连接:完成通信后,用`close()`函数关闭套接字...
- **读写数据**:服务器通过新创建的套接字与客户端进行数据交换,可以使用read和write(或者send/recv)函数。 - **关闭连接**:完成通信后,服务器关闭套接字,释放资源。 5. **协议设计**:描述中提到“只需写...
1. **创建ClientSocket**:使用`TcpClient`类实例化一个客户端套接字,通过构造函数指定服务器的IP地址和端口号。 2. **建立连接**:调用`TcpClient.Connect()`方法,向服务器发起连接请求。 3. **数据交换**:...
在C++中实现TCP/IP服务器,我们需要理解套接字(socket)编程,它是网络编程的核心。 1. **套接字创建**:在C++中,我们需要包含`<sys/socket.h>`和`<netinet/in.h>`等头文件,使用`socket()`函数创建一个套接字。...
**WinSock 套接字 TCP/IP 例程:客户端/服务器详解** 在计算机网络通信中,套接字(Socket)是一种重要的编程接口,它允许应用程序通过TCP/IP协议栈进行数据传输。本教程将深入讲解如何使用WinSock库在Visual ...
这个话题主要围绕如何使用Python来创建TCP/IP服务器和客户端,实现两者之间的数据交互。我们将深入讨论以下几个核心知识点: 1. **Python的socket库**:在Python中,`socket`模块是实现TCP/IP通信的基础。它提供了...
1. 初始化Socket对象:首先,创建一个新的Socket实例,指定其地址族(通常为InterNetwork)、套接字类型(Stream表示TCP)和协议类型(Tcp)。 2. 绑定与监听:服务器需要绑定到一个特定的IP地址和端口,并开始监听...
总的来说,"winsock window套接字 TCP/IP"是一个关于使用Windows套接字API进行TCP/IP通信的编程主题。通过VS2008工程,我们可以学习如何在Windows环境下构建可靠的网络应用,无论是客户端还是服务器端,都是基于...
当有客户端连接时,`accept()`函数会被用来接受连接并返回一个新的套接字,用于与客户端通信。 客户端程序则需要建立到服务器的连接。它同样先创建一个套接字,然后使用`connect()`函数尝试连接到服务器的指定IP和...
2. 连接服务器:获取服务器的IP地址和端口,使用TCP套接字进行连接。 3. 发送消息:用户输入消息后,客户端将消息封装成TCP数据包,通过套接字发送给服务器。 4. 接收消息:监听服务器的响应,接收到消息后在客户端...
通过套接字,服务器和客户端可以建立连接,发送和接收数据。 7. **数据交换格式**:在TCP/IP通信中,数据通常需要转换成特定的格式,如JSON、XML或自定义的二进制格式。服务器和客户端需要理解这种格式,才能正确...
同时,实验还将帮助我们掌握网络编程的基本技能,如套接字编程,以及如何处理并发连接。 总结来说,"TCP/IP实验客户端与服务器端"是一个全面了解网络通信基础的实践项目,它涵盖了从应用层到链路层的各个协议,并...
TCP/IP套接字编程不仅可以让开发者在不同的网络层级上进行灵活的数据通信,还能支持开发基于网络的客户端和服务器端应用程序。 TCP/IP套接字编程的基础是套接字API。在C#中,主要使用的类包括***, ***.Sockets以及...
在QT中实现TCP/IP服务器和客户端,我们可以利用QT提供的网络模块来构建基于套接字(socket)的通信。 TCP是一种面向连接的、可靠的传输协议,它确保了数据的顺序和完整性。在QT中,我们通常会使用`QTcpServer`和`...
2. **绑定和监听**:使用`bind()`函数将套接字与特定的IP地址和端口关联,然后用`listen()`函数设置服务器监听状态,准备接受客户端连接。 3. **接受连接**:当有客户端连接请求时,`accept()`函数会返回一个新的套...
当客户端发起连接请求时,服务器端的监听套接字会接受连接并返回一个新的套接字,通过这个新的套接字与客户端进行数据交换。服务器端还需要设计一个处理并发连接的机制,如多线程或异步I/O,以应对多个客户端同时...
TCP/IP通信客户端是网络编程中的一个关键组成部分,它允许设备或软件通过TCP/IP协议栈与服务器进行交互。在C++环境中开发TCP/IP客户端通常涉及到以下几个关键知识点: 1. **TCP/IP协议栈**:TCP(传输控制协议)和...
1. 创建一个Socket对象,指定IP地址类型(IPv4或IPv6)和套接字类型(TCP)。 2. 绑定Socket到特定的本地IP地址和端口号,调用Bind方法。 3. 开始监听客户端的连接,调用Listen方法设置最大连接队列长度。 4. 当有新...