Java中提供了socket编程来构建客户端和服务器端

TCP
构建服务器端的步骤:
(1)bind:绑定端口号
(2)listen:监听客户端的连接请求
(3)accept:返回和客户端连接的实例
(4)read/write:进行读写操作,也就是和客户端进行交互
(5)close:关闭资源
Java中提供了ServiceSocket关键字来构建服务器,在Java中listen和accept合并为一个accept操作,下面通过代码演示一下这5个步骤

public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket();
//bind:绑定ip和端口
serverSocket.bind(new InetSocketAddress(6666));
//listen监听并且accpet返回socket实例
Socket accept = serverSocket.accept();
//通过socket拿到输入流和输出流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(accept.getInputStream()));
PrintStream printStream = new PrintStream(accept.getOutputStream());
//读到客户端发来的数据并打印
String s = bufferedReader.readLine();
System.out.println("收到客户端的数据:"+s);
//向客户端输出数据
printStream.println("啦啦啦啦服务器回消息:"+s);
//关闭流和socket
printStream.close();
bufferedReader.close();
serverSocket.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
构建客户端的步骤:
(1)connect:通过IP地址和端口号连接服务器端
(2)read/write:进行读写操作,也就是和服务器端进行信息交流
(3)close:关闭资源
可以看到相比于服务器端,客户端的操作要简单很多
由于我们写的是TCP协议下的,所以要先启动服务器端,服务器端启动后,在accept会等待客户端的连接,也就是说代码在这里会阻塞住,客户端在这个时候连接就可以了。
下面用代码演示一下这几个步骤:

public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket();
//bind:绑定ip和端口
serverSocket.bind(new InetSocketAddress(6666));
//listen监听并且accpet返回socket实例
Socket accept = serverSocket.accept();
//通过socket拿到输入流和输出流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(accept.getInputStream()));
PrintStream printStream = new PrintStream(accept.getOutputStream());
//读到客户端发来的数据并打印
String s = bufferedReader.readLine();
System.out.println("收到客户端的数据:"+s);
//向客户端输出数据
printStream.println("啦啦啦啦服务器回消息:"+s);
//关闭流和socket
printStream.close();
bufferedReader.close();
serverSocket.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
这两个demo都用到了缓冲流和打印流来进行读写操作,下面看一下运行的结果

下面通过画图来描述一下这个过程

通过这幅图也会很清楚的知道三次握手和四次挥手分别发生在什么时候

下面想一个需求,如果是多个客户端和服务器端进行信息的交流怎么办?

刚才已经提到了,服务器端accpet操作是等待客户端连接的操作,那么写一个循环,每一个循环体里面有一个accept不就可以解决多个客户端连接服务器端的问题了,但是要注意一点的是accpet是一个阻塞操作,所以需要多个线程才可以,下面解释一下为什么:
首先需要明白的是只需要对服务器端进行修改即可,所以这块都是针对服务器端说的
如果只有一个线程,那么通过accpet连接上,那么这个线程还要用啦进行读写,在读写的时候也会阻塞,如果读写的时候阻塞了,那么下一个accpet就是不能正常连接的,线程就一直停到第一个连接上了,直到该连接完毕结束后才可以下一个连接,很明显这个过程是一个串行的过程,达不到所要的效果,这就需要多线程,主线程只用来保持连接(accpet),然后子线程负责和客户端进行读写交互,这样的话子线程在读写阻塞的时候是不会影响到主线程的。

下面先来看看多个客户端一个服务器端的代码:
下面的代码只展示服务器端,客户端和上面保持不变

public class MutileServer {
public static void main(String[] args) {
//创建有3个固定数量线程的线程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
try {
ServerSocket sockets = new ServerSocket(6666);
System.out.println("服务器已启动,正在等待连接");
while(true) {
Socket accept = sockets.accept();
System.out.println("客户端:"+accept.getInetAddress().getHostAddress());
executorService.execute(new MyThread(accept));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
class MyThread implements Runnable {
private Socket socket;
private BufferedReader bufferedReader;
private PrintStream printStream;
public MyThread(Socket socket) {
this.socket = socket;
try {
bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
printStream = new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}

@Override
public void run() {
try {
String s = bufferedReader.readLine();
System.out.println("客户端发来消息 "+s);
printStream.println("echo"+s);
printStream.flush();
bufferedReader.close();
printStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
需要说明的几点:
(1)这块我用到了线程池,不用多次创建线程,方便统一管理并且高效。也可以单独创建多个线程,通过循环也是可以的。
(2)我写了一个MyThread类专门用来处理读写和客户端的信息交流,也就是子线程完成读写操作,主线程只用关心和服务器端的连接即可。
(3)用完资源后必须关闭,并且尽量不要抛异常,在当前方法中处理一下。

缺点
用BIO实现TCP客户端和服务器端是有缺点的,BIO是同步阻塞模型,在JDK1.4之前一直使用这种模型,但是想这样一个问题,客户端每过来一个连接服务器端就要有一个线程与之对应,那么客户端非常多的情况下,服务器端线程就会非常多,而且线程上下文切换也会成为一笔非常大的消耗,这就是BIO的缺点,如果要改善这种缺点,就需要引入NIO。

UDP
UDP不像TCP是可靠的连接,也就是会保证数据的正确送达,而UDP会以数据报的形式扩散数据,举一个很简单的例子:听广播,当节目到达时必须提前打开收音机,这样才会保证不会错过。UDP也是一样,服务器端发送数据时,客户端需要提前等着,以免错过数据。
UDP完成客户端和服务器端需要两个类:DatagramPacket和DatagramSocket
DatagramSocket是建立连接的套接字,可以理解为运送货物的码头
DatagramPacket是数据包,也就是说数据在传送过程中是被打包成了数据包,如果DatagramSocket是码头,那么DatagramPacket就是装载货物的箱子。

看一下代码:
Server:

public class Server {
public static void main(String[] args) {
//要发送的数据
String data = "数据发送了。。。";
byte[] bytes = data.getBytes();

try {
//包装成数据包的形式
DatagramPacket packet = new DatagramPacket(bytes, bytes.length,InetAddress.getByName("127.0.0.1"), 8888);
//初始化DatagramSocket
DatagramSocket socket = new DatagramSocket();
//发送数据
socket.send(packet);
} catch (IOException e) {
e.printStackTrace();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Client:

public class Client {
public static void main(String[] args) {
try {
//选择监听的端口号
DatagramSocket socket = new DatagramSocket(8888);
//初始化接收数据包
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
//接收数据
socket.receive(packet);
//解析数据包
String s = new String(packet.getData(), 0,packet.getLength());
//打印接收到的数据
System.out.println(s);
} catch (IOException e) {
e.printStackTrace();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
先启动客户端,然后再启动服务器
---------------------

C/S模型:TCP,UDP构建客户端和服务器端(BIO实现的更多相关文章

  1. osi七层模型&tcp/udp

    1.TCP/UDP协议 1.1 TCP协议 可靠,速度慢,全双工通信 建立连接三次握手,断开连接四次挥手 建立起链接之后,发送每条消息都有回执,为了保证数据的完整性,还有重传机制 数据传输:有收必有发 ...

  2. 基于UDP的客户端和服务器端的代码设计

    实验平台 linux 实验内容 编写UDP服务器和客户端程序,客户端发送消息,服务器接收消息,并打印客户端的IP地址和端口号. 实验原理 UDP是无需连接的通信,其主要实现过程如下: 同样,我们可以按 ...

  3. Linux网络通信编程(套接字模型TCP\UDP与IO多路复用模型select\poll\epoll)

    Linux下测试代码: http://www.linuxhowtos.org/C_C++/socket.htm TCP模型 //TCPClient.c #include<string.h> ...

  4. TCP/UDP client/server library for Java, 最好的java语言tcp udp 服务器客户端实现库

    这个库andrdoi也可以用,而且是基于类的使用方式: 它支持类似聊天室的功能,即一个人说话,所有客户端都能收到,当然也支持点点通信.它还支持 RMI 的方式调用远程过程. https://githu ...

  5. QT 使用QUdpSocket QUdpServer UDP 建立客户端与服务器端

    1. 模拟天气监控,每隔两秒从Server发送天气信息到Client. 2. 示例代码 --------------------------- Server 端 ------------------- ...

  6. c++ 网络编程(一)TCP/UDP windows/linux 下入门级socket通信 客户端与服务端交互代码

    原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/9601511.html c++ 网络编程(一)TCP/UDP  入门级客户端与服务端交互代码 网 ...

  7. TCP/UDP端口列表

    http://zh.wikipedia.org/wiki/TCP/UDP%E7%AB%AF%E5%8F%A3%E5%88%97%E8%A1%A8 TCP/UDP端口列表     本条目可通过翻译外语维 ...

  8. TCP/UDP 常用端口列表

    计算机之间依照互联网传输层TCP/IP协议不同的协议通信,都有不同的对应端口.所以,利用短信(datagram)的UDP,所采用的端口号码不一定和采用TCP的端口号码一样.以下为两种通信协议的端口列表 ...

  9. TCP/UDP端口列表(WIKIpedia)

    计算机之间依照互联网传输层TCP/IP协议不同的协议通信,都有不同的对应端口.所以,利用短信(datagram)的UDP,所采用的端口号码不一定和采用TCP的端口号码一样.以下为两种通信协议的端口列表 ...

随机推荐

  1. Java正则表达式的用法

    /** * 校验时间格式,正确则返回true * @param xxx * @return */ private static boolean checkDateFormat (String xxx) ...

  2. c# 32位机和64位机 读取Excel内容到DataSet

    // ----------------------32位机 //注释说明 //ExclePath 为Excel路径 批号 是指Excel文件中某一列必填项 public static DataSet ...

  3. YTU 2414: C语言习题 字符串排序

    2414: C语言习题 字符串排序 时间限制: 1 Sec  内存限制: 128 MB 提交: 656  解决: 305 题目描述 输入n个字符串,将它们按字母由小到大的顺序排列并输出.编写三个函数实 ...

  4. 一步一步学Silverlight 2系列(4):鼠标事件处理

    一步一步学Silverlight 2系列(4):鼠标事件处理   概述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言V ...

  5. js验证form表单示例

    js验证form表单示例 检测测试了js表单验证,无jQuery(简单的功能有时无需jQuery版本) js代码如下:   <script type="text/javascript& ...

  6. I.MX6 逻辑分析仪 UART

    /*********************************************************************** * I.MX6 逻辑分析仪 UART * 说明: * ...

  7. BZOJ3732:Network(LCT与最小生成树)

    给你N个点的无向图 ( <= N <= ,),记为:…N. 图中有M条边 ( <= M <= ,) ,第j条边的长度为: d_j ( < = d_j < = ,,, ...

  8. Windows7下安装golang语言开发环境和revel框架

    1.下载先去下载32位或64 golang window 安装包 并安装下载地址:https://www.golangtc.com/download 本人更改了安装地址为 D:\GO\Go 2. go ...

  9. Python+页面元素高亮源码实例

    简单写了一个页面元素高亮的方法,原理就是在python中调用js实现元素高亮,分享一下源码如下: 1.元素高亮源码 Js调用 js = "var q=document.getElementB ...

  10. lua 与C通过c api传递table

    此文转自http://blog.csdn.net/perfect2011/article/details/19200511(感谢...) 首先了解下c++与lua之间的通信: 假设在一个lua文件中有 ...