--基本概念
所谓网络编程,就是让计算机之间进行相互通讯数据。
Java语言提供了一些相对简单的Api来完成这些通信工作,而Socket
就是其中之一,它存在于java.net包中。
网络编程的基本模型就是客户端到服务器模型。简单的
说就是两个进程之间相互通,然后其中一个必须提
供一个固定的位置,而另一个则只需要知道这个固定的
位置,并去建立两者之间的联系,然后完成数据的通讯
就可以了。这里提供固定位置的通常称为服务器,
而建立联系的通常叫做客户端。
Socket的基本工作过程包含以下四个步骤:
1 创建Socket;
2 打开连接到Socket的输入输出流;
3 按照一定的协议对Socket进行读写操作;
4 关闭Socket。
-----------服务端---------------
在Java中,服务端的建立采用的是ServerSocket类,
一个简单的使用示例如下:
---ServerSocket server=new ServerSocket(6789);
这里的6789表示的是服务端口,需要注意的是端口
的分配必须是唯一的。因为端口唯一标识计算机的
唯一服务。另外,端口号取值区间为0~65535
,但由于前1024(0~1023)个端口已经被TCP/IP作为保留端口,
因此可所分配的端口只能是1024之后的数字。
-----------客户端---------------
在Java中,客户端代码采用的是Socket类,
一个简单的使用示例如下:
---Socket socket=new Socket(InetAddress.getLocalHost(),6789)
这里的6789表示的是服务端口,客户端必须知道有关服
务器的IP地址或者其主机名。对于这一点Java也提供了
一个类InetAddress,该对象的实例必须通过它的静态方法
来提供。它的静态方法主要提供了得到本机IP 和通过名
字或IP直接得到InetAddress的方法。
-----------数据传输---------------
上面的方法基本可以建立一条连线让两台计算机相互交流了。
可是数据是如何传输的呢?
这里需要用到IO操作,它提供了针对于字节流和Unicode的读和写,
也提供了一个缓冲用于数据的读写。
---BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
---PrintWriter out=new PrintWriter(socket.getOutputStream());
上面两句就是建立缓冲并把原始的字节流转变为Unicode可以操作,
而原始的字节流来源于Socket的getInputStream()和getOutputStream()方法,
分别用来得到输入流和输出流。现在有了基本的模型和基本
的操作工具.
--------------------------------
TCP
服务器端
ServerSocket
服务端一般执行步骤如下:
1.创建一个ServerSocket实例,并指定本地端口
2.重复执行:
a)调用ServerSocket的accept()方法以获取下一个客户端连接。
基于新建立的客户端连接,创建一个Socket实例,由accept()方法返回。
b)使用返回的Socket实例的InputStream和OutputStream与客户端通信
c)通信完成后,使用Socket的close()方法关闭该客户端套接字连接。
所谓网络编程,就是让计算机之间进行相互通讯数据。
Java语言提供了一些相对简单的Api来完成这些通信工作,而Socket
就是其中之一,它存在于java.net包中。
网络编程的基本模型就是客户端到服务器模型。简单的
说就是两个进程之间相互通,然后其中一个必须提
供一个固定的位置,而另一个则只需要知道这个固定的
位置,并去建立两者之间的联系,然后完成数据的通讯
就可以了。这里提供固定位置的通常称为服务器,
而建立联系的通常叫做客户端。
Socket的基本工作过程包含以下四个步骤:
1 创建Socket;
2 打开连接到Socket的输入输出流;
3 按照一定的协议对Socket进行读写操作;
4 关闭Socket。
-----------服务端---------------
在Java中,服务端的建立采用的是ServerSocket类,
一个简单的使用示例如下:
---ServerSocket server=new ServerSocket(6789);
这里的6789表示的是服务端口,需要注意的是端口
的分配必须是唯一的。因为端口唯一标识计算机的
唯一服务。另外,端口号取值区间为0~65535
,但由于前1024(0~1023)个端口已经被TCP/IP作为保留端口,
因此可所分配的端口只能是1024之后的数字。
-----------客户端---------------
在Java中,客户端代码采用的是Socket类,
一个简单的使用示例如下:
---Socket socket=new Socket(InetAddress.getLocalHost(),6789)
这里的6789表示的是服务端口,客户端必须知道有关服
务器的IP地址或者其主机名。对于这一点Java也提供了
一个类InetAddress,该对象的实例必须通过它的静态方法
来提供。它的静态方法主要提供了得到本机IP 和通过名
字或IP直接得到InetAddress的方法。
-----------数据传输---------------
上面的方法基本可以建立一条连线让两台计算机相互交流了。
可是数据是如何传输的呢?
这里需要用到IO操作,它提供了针对于字节流和Unicode的读和写,
也提供了一个缓冲用于数据的读写。
---BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
---PrintWriter out=new PrintWriter(socket.getOutputStream());
上面两句就是建立缓冲并把原始的字节流转变为Unicode可以操作,
而原始的字节流来源于Socket的getInputStream()和getOutputStream()方法,
分别用来得到输入流和输出流。现在有了基本的模型和基本
的操作工具.
--------------------------------
TCP
服务器端
ServerSocket
服务端一般执行步骤如下:
1.创建一个ServerSocket实例,并指定本地端口
2.重复执行:
a)调用ServerSocket的accept()方法以获取下一个客户端连接。
基于新建立的客户端连接,创建一个Socket实例,由accept()方法返回。
b)使用返回的Socket实例的InputStream和OutputStream与客户端通信
c)通信完成后,使用Socket的close()方法关闭该客户端套接字连接。
注意:在关闭Socket时,相应的流也会关闭;反之,关闭流,Socket不会关闭。
聊天室代码演示:
服务端:
public class ServerDemo3 extends ServerSocket
{
private static final int SERVER_PORT = 2013;
/**
* 是否输出消息标志
*/
private static boolean isPrint = false;
/**
* 登录用户集合
*/
private static List user_list = new ArrayList();
/**
* 服务器已启用线程集合
*/
private static List<ServerThread> thread_list = new ArrayList<ServerThread>();
/**
* 存放消息队列
*/
private static LinkedList message_list = new LinkedList();
public ServerDemo3()
throws IOException
{
// 创建ServerSocket
super(SERVER_PORT);
// 创建向客户端发送消息线程
new PrintOutThread();
try
{
while (true)
{
// 监听客户端请求,启个线程处理
Socket socket = accept();
new ServerThread(socket);
}
}
catch (Exception e)
{
}
finally
{
close();
}
}
/**
* 监听是否有输出消息请求线程类,向客户端发送消息
*/
class PrintOutThread extends Thread
{
public PrintOutThread()
{
start();
}
@Override
public void run()
{
while (true)
{
if (isPrint)
{
// 将缓存在队列中的消息按顺序发送到各客户端,并从队列中清除。
String message = (String)message_list.getFirst();
for (ServerThread thread : thread_list)
{
thread.sendMessage(message);
}
message_list.removeFirst();
isPrint = message_list.size() > 0 ? true : false;
}
}
}
}
/**
* 服务器线程类
*/
class ServerThread extends Thread
{
private Socket client;
private PrintWriter out;
private BufferedReader in;
private String name;
public ServerThread(Socket s)
throws IOException
{
client = s;
out = new PrintWriter(client.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
in.readLine();//?
out.println("成功连上聊天室,请输入你的名字:");
start();
}
@Override
public void run()
{
try
{
int flag = 0;
String line = in.readLine();
while (!"bye".equals(line))
{
// 查看在线用户列表
if ("showuser".equals(line))
{
out.println(this.listOnlineUsers());
line = in.readLine();
}
// 第一次进入,保存名字
if (flag++ == 0)
{
name = line;
user_list.add(name);
thread_list.add(this);
out.println(name + "你好,可以开始聊天了...");
this.pushMessage("Client<" + name + ">进入聊天室...");
}
else
{
this.pushMessage("Client<" + name + "> say : " + line);
}
line = in.readLine();
}
out.println("byeClient");
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
// 用户退出聊天室
try
{
if(null != in)
{
in.close();
}
if(null != out)
{
out.close();
}
if(null != client)
{
client.close();
}
}
catch (IOException e)
{
e.printStackTrace();
}
thread_list.remove(this);
user_list.remove(name);
pushMessage("Client<" + name + ">退出了聊天室");
}
}
// 放入消息队列末尾,准备发送给客户端
private void pushMessage(String msg)
{
message_list.addLast(msg);
isPrint = true;
}
// 向客户端发送一条消息
private void sendMessage(String msg)
{
out.println(msg);
}
// 统计在线用户列表
private String listOnlineUsers()
{
String s = "--- 在线用户列表 ---\015\012";
for (int i = 0; i < user_list.size(); i++)
{
s += "[" + user_list.get(i) + "]\015\012";
}
s += "--------------------";
return s;
}
}
public static void main(String[] args) throws IOException
{
new ServerDemo3();// 启动服务端
}
}
-----------------------------------------------------
客户端:
public class ClientDemo3 extends Socket
{
private static final String LOCALHOST = "localhost";
private static final int SERVER_PORT = 2013;
private Socket client;
private PrintWriter out;
private BufferedReader in;
/**
* 与服务器连接,并输入发送消息
*/
public ClientDemo3()
throws Exception
{
super(LOCALHOST, SERVER_PORT);
client = this;
out = new PrintWriter(this.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(this.getInputStream()));
new readLineThread();
while (true)
{
in = new BufferedReader(new InputStreamReader(System.in));
String input = in.readLine();
out.println(input);
}
}
/**
* 用于监听服务器端向客户端发送消息线程类
*/
class readLineThread extends Thread
{
private BufferedReader buff;
public readLineThread()
{
try
{
buff = new BufferedReader(new InputStreamReader(client.getInputStream()));
start();
}
catch (Exception e)
{
}
}
@Override
public void run()
{
try
{
while (true)
{
String result = buff.readLine();
if ("byeClient".equals(result))
{//客户端申请退出,服务端返回确认退出
break;
}
else
{//输出服务端发送消息
System.out.println(result);
}
}
in.close();
out.close();
client.close();
}
catch (Exception e)
{
}
}
}
public static void main(String[] args)
{
try
{
new ClientDemo3();//启动客户端
}
catch (Exception e)
{
}
}
}