java网络编程之一对一的socket C/S通信

时间:2021-05-25 19:33:45

一对一的Socket C/S通信

TCP是一种可靠地、基于连接的网络协议。当两台主机准备进行交谈时,都必须建立一个Socket,其中一方作为服务器打开一个Socket并侦听来自网络的连接请求,另一方作为客户,它向网络上的服务器发送请求,通过Socket与服务器传递消息,要建立连接,只需要指定主机的IP地址和端口号即可。

TCP协议通信的服务方实现

服务程序工作在服务器的某个端口上,一旦启动服务,它将在这个端口上侦听,等待客户程序发来的请求。服务器的套接字用服务器套接字类(ServerSocket)来建立。假设服务器工作在端口8000上,以下命令:

SeverSocket sever = new SeverSocket8000);

建立了一个服务者sever,它监视端口8000。命令

Socket soc = sever.accept();

让服务者永远等待,直到客户连接到该端口上,一旦有客户送来正确的请求,连接到该端口accept()方法就返回一个Socket对象,表示已经建立好连接,可用Socket的队形soc获得一个输入/输出流,如下:

DataInputStream in = new DataInputStreamsoc.getInputStream());

PrintStream out = new PrintStreamsoc.getOutputStream());

这里创建了数据输入流类的实例in和输出流类的实例out,是服务者用于从客户接搜输入信息和向客户程序发送信息所用,同样在客户端,也应该建立者两个实例,用来与服务程序进行双向通信。服务者向输入流发送的所用信息都成为客户的输入信息,而客户程序的输出都送入服务者的输入流。

获取主机的IP地址,并在服务者窗口中显示客户机的地址信息:

clientIP = soc.getInetAddress();

System.out.println(“Client’s IP address: ”+clientIP);

println()是输出流类的一个方法,下行向客户送一句问候:

out.println(“Wlcome...”)

当用远程登录通过端口8000连接到该服务者时,客户终端屏幕上将接受到上述信息。

该简单服务中,每次只读入一行客户的输入,并回显该行,以表明服务者接受了客户的输入。

readLine()是数据输入流类中的一个方法,用于服务者或客户从对方读入一个输入流信息:

String str = in.readLine()

While!str.equals(“quit”)

{

System.out.println(“Client said:” +str());

str=in.readLine();

}

不断循环以上代码,知道客户输入“quit”或者strnull为止;最后在退出前,关闭输入Socket

System.out.println(“Client want to leave”);

finally{

in.close()

out.close();

soc.close();

server.close();

}

这就是一个简单的回应服务者的工作过程。每一个服务者,如HTTP Web服务者,都是不停地执行下列循环:

(1)通过输入流向客户获得命令;

(2)以某中方式获取该信息;

(3)通过输出流将信息送给给客户。 

TCP协议通信的客户方式实现

客户机先创建一个指向固定主机的固定端口的Socket,加入上述服务者程序在本机“localhost”上,则以下命令:

Socket soc = new Socket(“localhost”,8000);

/*

*三种方法获取本机IP地址:

* 1,Socket soc = new SocketInetAddress.getByName("localhost"),8000);
* 2,Socket soc = new SocketInetAddress.getByName("127.0.0.1"),8000);本机回路地址

* 3,Socket soc = new SocketInetAddress.getByName(null),8000);

*/

建立了客户到服务者的连接,两端进行通信的通路即建立。当服务者接受该连接请求时,Socket实例soc即建立,同样,从该Socket实例中获取输入和输出流:

in = new DataInputStreamsever.getInputStream());

out = new PrintStream(sever.getOutputStream());

输入/输出流建立后,客户首先从客户奇读取发来的“Welcome...”信息,显示在窗口中:

strin = in.readLine();

System.out.println(“Sever said:”+strin);

这两行命令执行后,窗口中应显示出服务者的欢迎信息和客户机系统输出的信息。

客户想服务者发送的数据流从键盘获得:

sysin = new DataInputStreamSystem.in);

strout = sysin.readLine();

当键盘输入不是“quit”时,将键盘输入的数据写入输出流中,并发送出去,然后继续从键盘后去输入数据:

out.println(strout);

strout = sysin.readLine();

不断循环上述两行命令,直到键盘输入“quit”后,现将其传送给服务者,然后关闭输入/输出流和Socket

out.println(strout);

in.close()

out.close();

sysin.close();

server.close();

该客户是与同一台主机上的回应服务者进行通信,先进行服务程序,再运行客户程序,运行结果如下:

在服务进程窗口中显示:

Client’s IP address127.0.0.1

Client saidHello

Client want to leave.

在客户进程窗口中显示:

Connecting to the Server...

Sever said:Welcome!...

Hello!

quit

其中后面三行是客户的键盘输入。如果要在网络中的两台不同计算机之间进行通信,秩序将Socket()中传递的参数“localhost”改成相应的主机名或者IP即可。

源代码: 

import java.io.DataInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class Sever {
	static public void main(String args[])
	throws IOException
	{
		ServerSocket sersoc = null;
		Socket soc = null;
		DataInputStream  in = null;
		PrintStream out = null;
		InetAddress clientIp = null;
		String str = null;
		try {
			sersoc = new ServerSocket(8000);
			soc = sersoc.accept();
			in = new DataInputStream(soc.getInputStream());
			out = new PrintStream(soc.getOutputStream());
			clientIp = soc.getInetAddress();
			System.out.println("Client's IP address: "+clientIp);
			out.println("Welcome!...");
			str = in.readLine();
			while(!str.equals("quit"))
			{
				System.out.println("Client said: "+str);
				str = in.readLine();
			}
			System.out.println("Client want to leave.");
		} catch (Exception e) {
			System.out.println("Error: "+e);
		}
		finally
		{
			in.close();
			out.close();
			soc.close();
			sersoc.close();
			System.exit(0);
		}
	}
}


import java.io.DataInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;

public class Client {
	static public void main(String args[])
	throws IOException
	{
		Socket soc = null;
		DataInputStream in = null;
		PrintStream out = null;
		DataInputStream sysin = null;
		String strin = null;
		String  strout = null;
		
		try {
			soc = new Socket(args[0],8000);
			System.out.println("Connecting to the Server...");
			in = new DataInputStream(soc.getInputStream());
			out = new PrintStream(soc.getOutputStream());
			strin = in.readLine();
			System.out.println("Sever said: "+strin);
			sysin = new DataInputStream(System.in);
			strout = sysin.readLine();
			while (!strout.equals("quit")) {
				out.println(strout);
				strout = sysin.readLine();
				}
			out.println(strout);
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println("Error: "+e);
		}
		finally
		{
			in.close();
			out.close();
			sysin.close();
			soc.close();
			System.exit(0);
		}
	}
}

API注释:套接口类(java.net.Socket)

1)SocketString host,int portthrows UnknownHostException,IOException

创建一个流套接口(即Socket实体对象),并将其连接至特定主机的特定端口上。

参数: host  主机名

port  端口号

2)SocketString hostint portboolean stream

构造一个套接口(即Socket实体对象),并把它连接到特定主机的特定端口上。而此套接口是流套接口还是数据报(datagram)套接口,则是由最后一个参数stream决定。

参数: host 主机名

port 端口号

stream 用于决定生成的套接口是流套接口还是数据报套接口 (datagram socket

3)SocketInetAddress addressint port

构造一个套接口(即Socket实体对象),并把它连接到特定主机的特定地址上。参数: address 特定的地址

port 端口

4)SocketInetAddress addressint portboolean stream

构造一个流套接口(即Socket实体对象),并把它连接到特定端口的特定地址上。而此套接口是流套接口还是数据报(datagram)套接口,则是有最后一个参数stream决定的。

参数: host 主机名

port 端口号

stream 用于决定生成的套接口是流套接口还是数据报套接口 (datagram socket

5)InetAddress getInetAddress()

返回该套接口(socket)所连接的地址。

6)int getPort()

返回该套接口(socket)所连接的远程端口。

7)synchronized void close()throws IOException

关闭套接口。

8InputStream getInputStream()throws IOException

获得从套接口读入数据的输入流。

注:DataInputStreamInputStream的子类

9)OutputStream getOutputStream() throws IOException

获得向套接口进行读操作的输入流。

注:PrintStreamOutputStream的子类。 

API注释:服务者套接口类(java.net.ServerSocket

1)ServerSocketint portthrows IOException

在指定的端口上构造一个服务者套接口,即构造一个ServerSocket实体对象。

参数: port 端口号

2)ServerSocketint portint count

构造一个服务者套接口,即构造一个ServerSocket实体对象,并且该对象时与指定的当地端口相连接的。此外,可以对它进项监听。用户也可以通过将port设置为0来将该对象与一个匿名端口相连接。

参数: port 端口号

count 对该ServerSocket实体对象与端口间的连接进行监听的 次数。

3)Socket accept()throws IOException

等待一个连接,该方法将阻塞当前线程,知道连接成功。该方法返回一个套接口类(Socket)对象,通过该对象,程序与链接的客户进行通信。

4)void close()throws IOException

关闭套接口。