比尔最近接到一个项目是要在原来的系统上实现客户端与服务器的连接原来的系统是用Java开发的项目组讨后决定应用Java提供的Socket类来解决问题比尔是C开发的高手对Java却只略知皮毛所以比尔一头扎进Java中开始他的学习历程当然首先还要解决眼前的问题学习Socket编程
在学习Socket编程之前先看看自己是否熟悉TCPUDPPorts等网络基本概念要是还不熟悉的话就得先去补补课罗!
Socket 的基本概念
Socket也就是俗称的套接字
Sun Java中的定义是运行在网络上的两个程序间双向通讯连接的末端它提供客户端和服务器端的连接通道Socket绑定于特定端口这样TCP层就知道将数据提供给哪个应用程序
字面上的理解Socket的意思是插座孔你还可以把它形象地理解为打电话用的电话机你从听筒里听到对方声音同时将声音通过话筒传给对方
我想你现在和我刚开始的时候一样好像有点明白又好像不是很明白没关系我希望通过下面例子的讲解你能够彻底地掌握它在实例之前让我们先来看看Socket实现的基本原理
Socket编程实现原理
从连接的建立到连接的结束每个Socket应用都大致包含以下几个基本步骤
服务器端socket绑定于特定端口服务器侦听socket等待连接请求
客户端向服务器和特定端口提交连接请求
服务器接受连接产生一新的socket绑定到另一端口由此socket来处理和客户端的交互服务器继续侦听原socket来接受其他客户端的连接请求
连接成功后客户端也产生一socket并通过它来与服务器端通讯(注意客户端socket并不与特定端口绑定)
接下来服务器端和客户端就通过读取和写入各自的socket来进行通讯
注意本文中只讲解基于TCP的Socket应用
Java中的Socket类
Java中提供两个类(在包中)——Socket和ServerSocket来分别实现客户端和服务器端Socket但Socket的实际工作是由抽象类SocketImpl的实例来完成的这其实是设计模式中Abstract Factory模式的一个应用
ServerSocket类的常用构造器和主要方法
ServerSocket(int port)在指定的端口号上产生一服务器端socket
Socket accept()
侦听socket接受连接
Socket类的常见构造器和主要方法
Socket(String host int port)生成一socket并连接至指定的主机和端口
InputStream getInputStream()返回socket的输入流
OutputStream getOuputStream() 返回socket的输出流
一个客户服务器实例
了解了上面的一些基本知识以后我想大家现在都迫不及待地想亲自动手编写自己的socket那就让我们开始吧!在这个例子中我们模仿了一个Echo服务它侦听端口客户端接受用户键盘输入并向服务器端发出连接请求服务器端接受客户端连接连接成功后建立会话客户端于是向服务器端发送用户输入信息服务器端接收此信息并且简单返回给客户端源码如下
(服务器端)
/**
* <p>Title:EchoServerjava </p>
* <p>Description: EchoServer create a echolike server at port </p>
* @author Mac
* @version //
*/
import *;
import javaio*;
public class EchoServer
{
public static void main (String[] args) throws IOException
{
ServerSocket echoServer = null;
try
{
echoServer = new ServerSocket(); //creat a server socket at port
(问题一)
}
catch(IOException e)
{
Systemerrprintln("Couldnt listen on port:");
Systemexit();
}
Socket echoClient = null;
try
{
echoClient = echoServeraccept(); //accept a connection
}
catch(IOException e)
{
Systemerrprintln("IO error:" + egetMessage());
Systemexit();
}
PrintWriter out = new PrintWriter(echoClientgetOutputStream()true);
//gets the sockets output stream and opens a PrintWriter on it
//if you remove the argument truewhat will happen?(问题三)
BufferedReader in = new BufferedReader(
new InputStreamReader(echoClientgetInputStream()));
//gets the sockets input stream and opens a BufferedReader on it
String strFromClient;
while((strFromClient = inreadLine()) != null)
{
outprintln("result is :" + strFromClient);
}
inclose();
outclose();
echoClientclose();
echoServerclose();
}
}
(客户端)
/**
*<p>Title:EchoClientjava </p>
*<p>Description: EchoClient creates a socket thereby getting a connection to
echolike server</p>
* @author Mac Wang
* @version //
*/
import *;
import javaio*;
public class EchoClient
{
public static void main(String[] args)
{
try
{
Socket echoClient = new Socket("yourhostname");
//creat a new socket connected to host and port
PrintWriter out = new PrintWriter(echoClientgetOutputStream()true);
BufferedReader in = new BufferedReader(
new InputStreamReader(echoClientgetInputStream()));
String fromServerfromUser;
BufferedReader stdIn = new BufferedReader(
new InputStreamReader(Systemin));
//gets the system input stream and opens a BufferedReader on it
while ((fromUser = stdInreadLine()) != null)
{
if (fromUserequals("bye")) break;
//when user types "bye" then end
Systemoutprintln("input is:" + fromUser);
outprintln(fromUser);
fromServer = inreadLine();
Systemoutprintln(fromServer);
}
outclose();
inclose();
echoClientclose();
}
catch(UnknownHostException e)
{
Systemerrprintln("Unknown host:yourhostname");
Systemexit();
}
catch(IOException e)
{
Systemerrprintln("I/ error:" + egetMessage());
Systemexit();
}
}
}
现在大家可以分别运行Server和Client看看程序运行效果(注意你必须将yourhostname替换成你自己的主机名或IP地址)并且思考以下几个问题
把端口号换成后看看程序运行效果?那么呢?是不是任何数字都可以呢?
如果不采用我们自己编写的echo server而是连接到系统本身提供的echo server(端口号为)试试看会发生什么情况客户端Socket是否需要改变呢?
去掉PrintWriter中的参数True看看程序运行的效果?
注意程序中是如何读取和写入Socket的?
试着多打开几个客户端看看效果如何?
从问题中大家可以看出来上面的例子只支持一个用户连接那么如何支持多用户的同时访问呢?最简单有效的方法就是利用多线程实现每个线程对应一个用户连接server接受一个client连接后就新产生一个线程并交由它去处理余下的工作下面就是支持多用户的服务器端实现
/**
*<p>Title:EchoMultiServer </p>
*<p>Description: EchoServer create a echolike server at port which supports
multiclient</p>
* @author Mac Wang
* @version //
*/
import *;
import javaio*;
class EchoMultiServerThread extends Thread
{
private Socket echoClient = nul