一、ServerSocket
ServeSocket负责客户端的接收,并生成客户端的连接请求
1、构造方法
- ServerSocket() throws IOException
//绑定到服务器上的任意一个可用的端口
- ServerSocket(int) throws IOException
//绑定服务器上指定的端口
- ServerSocket(int, int) throws IOException
//绑定到服务器山指定的端口并且指定客户端请求的长度(当客户端等待连接的队列达到设定的容量的时候,服务器会拒绝和客户端的连接请求)
- ServerSocket(int, int, InetAddress) throws IOException
//绑定到服务器上的指定的端口并且指定客户端的请求长度和绑定服务器上的指定的Ip地址
2、主要方法
- public Socket accept() throws IOException {}
//ServerSocket的accept()方法会从客户端的请求队列中取出一个请求连接,然后创建与客户端连接的Socket对象。如果请求队列中没有,那么accept()会一直等待,知道有客户端请求连接
- public void close() throws IOException {}
//使得服务器释放所占用端口,并且断开与所有的客户端的连接。当一个服务器程序运行完毕的时候,即使没有执行close()方法,操作系统也会释放服务器所占用的端口
- public boolean isClosed() {}
//判断服务器程序所占用的端口是否被释放,如果是那么返回true ,否则返回false
- public synchronized void setSoTimeout(int timeout) throws SocketException {}
//设置等待客户端连接的超时的时间
- public synchronized int getSoTimeout() throws IOException {}
//获取等待客户端连接的超时时间
- public synchronized void setReceiveBufferSize (int size) throws SocketException {}
//设置服务器接收缓冲区的大小
- public synchronized int getReceiveBufferSize()
//获取服务器接收缓冲区的大小
- public void setReuseAddress(boolean on) throws SocketException {}
//是否允许网络上的数据向旧的serversocket发送数据,比如网络上还有客户端发送的数据,服务器断开了serversocket,如果这里设置为true那么便会允许向新的serversocket发送数据
- public boolean getReuseAddress() throws SocketException {}
//获取是否允许网络的数据向旧的serversocket发送数据
二、Socket
套接字可以看成是两个网络应用程序进行通信时,各自通信连接中的一个端点。通信时,其中的一个网络应用程序将要传输的一段信息写入它所在主机的Socket中,该Socket通过网络接口卡的传输介质将这段信息发送给另一台主机的Socket中,使这段信息能传送到其他程序中。因此,两个应用程序之间的数据传输要通过套接字来完成。 [2]
在网络应用程序设计时,由于TCP/IP的核心内容被封装在操作系统中,如果应用程序要使用TCP/IP,可以通过系统提供的TCP/IP的编程接口来实现。 [3] 在Windows环境下,网络应用程序编程接口称作Windows Socket。为了支持用户开发面向应用的通信程序,大部分系统都提供了一组基于TCP或者UDP的应用程序编程接口(API),该接口通常以一组函数的形式出现,也称为套接字(Socket)。 ----百度百科
1、构造函数
public Socket() {}
//无参构造函数,直接绑定到本机上,任意一个可用的端口
public Socket(String host, int port) throws UnknownHostException, IOException.
//传入目标服务器的地址和服务器程序所占用的端口
Socket(InetAddress, int) throws IOException
//传入InetAddress和端口号进行初始化
Socket(Proxy)
//通过代理进行初始化
2、方法描述
public void connect(SocketAddress host, int timeout) throws IOException
//将此套接字连接到服务器,并指定一个超时值。
public SocketAddress getRemoteSocketAddress()
//返回此套接字连接的端点的地址,如果未连接则返回 null。
public InputStream getInputStream() throws IOException
//返回此套接字的输入流。
public OutputStream getOutputStream() throws IOException
//返回此套接字的输出流。
三、原理
对于客户端/服务器(C/s)结构,即通信双方一方作为服务器等待客户提出请求并予以响应。客户需要服务的时候想服务器提出申请,而服务器一般作为守护进程始终运行,监听网络端口,一旦有客户的请求,就会启动一个服务进程来响应客户,同时自己会继续监听服务器端口,对于浏览器(B/S)结构,客户在需要服务时向服务器进行请求,服务器及时返回,不需要实时监听端口
四、代码实现
1个客户端和1个服务器
服务器端:
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket=new ServerSocket(9999);
Socket socket= serverSocket.accept();
//创建套接字
BufferedWriter bufferedWriter=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bufferedWriter.write("你哈");
bufferedWriter.newLine();
bufferedWriter.flush();
bufferedWriter.close();
}
}
客户端
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket=new Socket("localhost",9999);
String message=null;
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
message = bufferedReader.readLine();
System.out.println("客户端所接受到的数据为----->"+message);
}
}
实现结果:
客户端所接受到的数据为----->你哈
2、使用线程来对客户端的向服务器发送数据和接受服务器的数据
接收线程:
mport java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
public class Receive implements Runnable {
private DataInputStream dis;
private boolean isRunning=true;
public Receive() {
// TODO 自动生成的构造函数存根
}
public Receive(Socket socket)
{
try {
dis=new DataInputStream(socket.getInputStream());
} catch (IOException e) {
// TODO 自动生成的 catch 块
// e.printStackTrace();
isRunning=false;
try {
CloseUtil.CloseAll(dis);
} catch (IOException e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
}
}
}
public String receive()
{
String message="";
try {
message=dis.readUTF();
System.out.println("客户端收到的数据为---->"+message);
} catch (IOException e) {
// TODO 自动生成的 catch 块
// e.printStackTrace();
isRunning=false;
try {
CloseUtil.CloseAll(dis);
} catch (IOException e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
}
}
return message;
}
@Override
public void run() {
// TODO 自动生成的方法存根
while(isRunning)
{
receive();
}
}
}
发送线程
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
public class Send implements Runnable {
private BufferedReader console;
private DataOutputStream dataoutputStream;
private boolean isrunning=true;
//对数据进行初始化
Send()
{
console=new BufferedReader(new InputStreamReader(System.in));
}
//传入Socket参数进行初始化
Send(Socket socket) throws IOException
{
this();
try
{
dataoutputStream=new DataOutputStream(socket.getOutputStream());
}
catch(Exception e)
{
e.printStackTrace();
isrunning=false;
}
}
//从控制台获取信息
public String getMsgFromConsole()
{
try {
String meString=console.readLine();
return meString;
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
return "";
}
//发送相关的信息
public void send() throws IOException
{
String meString=getMsgFromConsole();
if(null!=meString&&!meString.equals(""))
{
try {
dataoutputStream.writeUTF(meString);
dataoutputStream.flush();
} catch (IOException e) {
// TODO 自动生成的 catch 块
// e.printStackTrace();
isrunning=false;
CloseUtil.CloseAll(dataoutputStream,console);
}
}
}
@Override
public void run() {
// TODO 自动生成的方法存根
try {
while(isrunning)
{
send();
}
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
客户端调用:
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
//客户端
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket client=new Socket("localhost",9999);
String message=null;
new Thread(new Send(client)).start();//一条路径
new Thread(new Receive(client)).start();//另一条路径
}
}
服务端调用
import java.io.Closeable;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import Internet.CloseUntil;
/*
* 这是服务器端
*/
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket=new ServerSocket(9999);
Socket socket= serverSocket.accept();
//输入流
DataInputStream dataInputStream=new DataInputStream(socket.getInputStream());
//服务器发送相关的数据
DataOutputStream dataOutputStream=new DataOutputStream(socket.getOutputStream());
while(true)
{ String str=dataInputStream.readUTF();
System.out.println("服务器收到的数据为"+str);
dataOutputStream.writeUTF(str);
System.out.println("服务器进行转发的数据为---->"+str);
dataOutputStream.flush();
}
}
}
实现结果:
a
客户端收到的数据为---->a
服务器收到的数据为a
服务器进行转发的数据为---->a
3、1个服务器和多个客户端
这里只是修改了server,其他代码与2相同
服务器端:
import java.util.List;
import java.io.Closeable;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import javax.print.attribute.standard.MediaName;
import Internet.CloseUntil;
/*
* 这是服务器端
*/
public class Server {
private List<Mychannel> all=new ArrayList<Mychannel>();
public static void main(String[] args) throws IOException {
new Server().start();
}
public void start() throws IOException
{ ServerSocket serverSocket=new ServerSocket(9999);
Socket socket= serverSocket.accept();
Mychannel mychannel=new Mychannel(socket);
all.add(mychannel);
}
class Mychannel implements Runnable {
private DataInputStream dis;
private DataOutputStream dos;
private boolean isRunning =true;
public Mychannel(Socket client) throws IOException {
// TODO 自动生成的构造函数存根
try {
dis=new DataInputStream(client.getInputStream());
dos=new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
// TODO 自动生成的 catch 块
// e.printStackTrace();
CloseUtil.CloseAll(dis,dos);
isRunning=false;
all.remove(this);
}
}
private String Receive() throws IOException
{ String message=null;
try {
message= dis.readUTF();
} catch (IOException e) {
// TODO 自动生成的 catch 块
//e.printStackTrace();
isRunning=false;
CloseUtil.CloseAll(dis,dos);
all.remove(this);
}
return message;
}
private void send(String message) throws IOException
{
if(message!=null&&!message.equals(""))
{
try {
dos.writeUTF(message);
dos.flush();
} catch (IOException e) {
// TODO 自动生成的 catch 块
// e.printStackTrace();
isRunning=false;
CloseUtil.CloseAll(dos,dis);
all.remove(this);
}
}
}
private void sendOthers() throws IOException
{
String message=Receive();
for (Mychannel mychannel : all) {
if(mychannel==this)
{
continue;
}
else
{
mychannel.send(message);
}
}
}
@Override
public void run() {
// TODO 自动生成的方法存根
while(isRunning)
{
try {
sendOthers();
} catch (IOException e) {
// TODO 自动生成的 catch 块
//e.printStackTrace();
isRunning=false;
all.remove(this);
try {
CloseUtil.CloseAll(dis,dos);
} catch (IOException e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
}
}
}
}
}
}