用Java实现简单的网络聊天程序
Socket套接字定义:
套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。网络套接字是IP地址与端口的组合。
Socket的英文原义是“孔”或“插座”。在网络编程中,网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个Socket。
Socket套接字是通信的基石,是支持
TCP/IP协议
的网络通信的基本操作单元。
它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。Socket本质是
编程接口(API)
,对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口。
Socket 调用流程:
socket():创建套接字。
bind():指定本地地址。一个套接字用socket()创建后,它其实还没有与任何特定的本地或目的地址相关联。在很多情况下,应用程序并不关心它们使用的本地地址,这时就可以不用调用bind指定本地的地址,而由协议软件为它们选择一个。但是,在某个知名端口(Well-known Port)上操作的服务器进程必须要对系统指定本地端口。所以一旦创建了一个套接字,服务器就必须使用bind()系统调用为套接字建立一个本地地址。
connect():将套接字连接到目的地址。初始创建的套接字并未与任何外地目的地址关联。客户机可以调用connect()为套接字绑定一个永久的目的地址,将它置于已连接状态。对数据流方式的套接字,必须在传输数据前,调用connect()构造一个与目的地的TCP连接,并在不能构造连接时返回一个差错代码。如果是数据报方式,则不是必须在传输数据前调用connect。如果调用了connect(),也并不像数据流方式那样发送请求建连的报文,而是只在本地存储目的地址,以后该socket上发送的所有数据都送往这个地址,程序员就可以免去为每一次发送数据都指定目的地址的麻烦。
listen():设置等待连接状态。对于一个服务器的程序,当申请到套接字,并调用bind()与本地地址绑定后,就应该等待某个客户机的程序来要求连接。listen()就是把一个套接字设置为这种状态的函数。
accept():接受连接请求。服务器进程使用系统调用socket,bind和listen创建一个套接字,将它绑定到知名的端口,并指定连接请求的队列长度。然后,服务器调用accept进入等待状态,直到到达一个连接请求。
send()/recv()和sendto()/recvfrom():发送和接收数据 。在数据流方式中,一个连接建立以后,或者在数据报方式下,调用了connect()进行了套接字与目的地址的绑定后,就可以调用send()和reev()函数进行数据传输。
closesocket():关闭套接字。
TCP 三次握手四次断开的工作原理图:
服务端 server.java 代码:
1.创建ServerSocket对象,绑定监听端口。
2.通过accept()方法监听客户端请求。
3.连接建立后,在接收进程中通过输入流读取客户端发送的请求信息。
4.在服务器发送进程中通过输出流向客户端发送响应信息。
5.关闭相应的资源和Socket。
package hello_hi; import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket; public class server {
public static void main(String[] args) throws Exception {
// 监听指定的端口,阻塞直至客户端连接此端口
int port = 2199;
ServerSocket server = new ServerSocket(port);
// new ServerSocket(port)创建端口,包括socket() bind() listen() 3个API的调用
System.out.println("服务端在等待连接客户端...");
Socket socket = server.accept(); //调用API:accept()等待client的消息
System.out.println("连接到客户端!"); // 读取从客户端返回的输入流,至尾端时返回-1
InputStream input = socket.getInputStream();
byte[] bytes = new byte[1024];
int len;
StringBuilder get = new StringBuilder();
while ((len = input.read(bytes)) != -1) { //调用API:input.read()
get.append(new String(bytes, 0, len, "UTF-8"));
}
System.out.println("弟弟1号: " + get); OutputStream output = socket.getOutputStream();
String sent = "Hello 弟弟~";
output.write(sent.getBytes("UTF-8"));
System.out.println("发送消息: " + sent); // 关闭socket与服务器端
input.close();
output.close();
socket.close();
server.close();
}
}
客户端 client001.java 代码:
1.创建Socket对象,指明需要连接的服务器的地址和端口号。
2.连接建立后,通过输出流向服务器发送请求信息。
3.通过输入流获取服务器响应的信息。
4.关闭相应资源。
package hello_hi; import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket; public class client001 {
public static void main(String args[]) throws Exception {
// 连接本地主机,端口自设,与服务端一致即可
String host = "127.0.0.1"; //本机IP
int port = 2199; //端口号port
// 通过socket与服务端建立连接
Socket socket = new Socket(host, port);// host+port = IP+端口号
if(socket.isConnected()){
System.out.println("连接到服务端!");
}
// 将要发送的信息写入输出流
OutputStream output = socket.getOutputStream();
String sent = "Hi 大哥好!";
socket.getOutputStream().write(sent.getBytes("UTF-8"));
// 关闭客户端的输出流(单向,并未关闭socket)
socket.shutdownOutput();
System.out.println("发送消息: " + sent); // 读取从server返回的输入流
InputStream input = socket.getInputStream();
byte[] bytes = new byte[1024];
int len;
StringBuilder get = new StringBuilder();
while ((len = input.read(bytes)) != -1) {
get.append(new String(bytes, 0, len,"UTF-8"));
}
System.out.println("大哥: " + get); // 关闭socket
input.close();
output.close();
socket.close();
}
}
程序运行结果(使用IDEA编辑器):
(1)服务端等待客户端连接(运行 server.java,但未运行 client001.java):
(2)服务端连接上客户端,接收、发送消息:
(3)客户端连接上服务器,发送消息、接收消息
阶段总结:
由于第一次接触socket编程(also Java...)比较仓促,至少有以下几点可以提高的地方:
1.通信循环输入输出,使用while()结构实现。
2.有了1的话,可以持续对话,但是只能你一句我一句,不能一个人连续多句话。所以还需要连续发送功能,这个需要整个重构,一方发送一方及时接收。
3.不能多人(群)对话,具体实现有待学习。。
JAVA Socket API分析
以 Socket 为例子:
再查看 SocketImpl:
再查看 ServerSocket:
其中的大量调用关系比较复杂,还不是完全清楚。。
Socket总结:
套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。
服务器监听:建立服务器端套接字,并处于等待连接的状态,不定位具体的客户端套接字,而是实时监控网络状态。
客户端请求:是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。 为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
连接确认:是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端, 一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。 上图为基于TCP协议Socket的通信模型。
用Java实现简单的网络聊天程序的更多相关文章
- hello/hi的简单的网络聊天程序
hello/hi的简单的网络聊天程序 0 Linux Socket API Berkeley套接字接口,一个应用程序接口(API),使用一个Internet套接字的概念,使主机间或者一台计算机上的进程 ...
- 以您熟悉的编程语言为例完成一个hello/hi的简单的网络聊天程序
Socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信,应用程序通常通过"套接字"向网络发出 ...
- 以C语言为例完成简单的网络聊天程序以及关于socket在Linux下系统调用的分析
套接字是网络编程中的一种通信机制,是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程. 端 ...
- python实现一个简单的网络聊天程序
一.Linux Socket 1.Linux Socke基本上就是BSD Socket(伯克利套接字) 伯克利套接字的应用编程接口(API)是采用C语言的进程间通信的库,经常用在计算机网络间的通信.B ...
- telnet指令研究—以网络聊天程序为例
一.telnet指令 Telnet取名自Telecommunications和Networks的联合缩写,是早期个人计算机上连接到服务器主机的一个网络指令,由于存在安全问题,现在已经很少被使用.在wi ...
- C# 异步通信 网络聊天程序开发 局域网聊天室开发
Prepare 本文将使用一个NuGet公开的组件技术来实现一个局域网聊天程序,利用组件提供的高性能异步网络机制实现,免去了手动编写底层的困扰,易于二次开发,扩展自己的功能. 在Visual Stud ...
- java编写简单的语法分析预测程序
编译原理课程中,编了一个简单的语法分析预测程序,这个程序时根据固定的文法得到预测分析表,然后编写程序来判断表达式是否会正确推到出来. 前提是程序没有左递归符合LL(1)文法: 文法如下: E→TE' ...
- boost asio异步读写网络聊天程序client 实例具体解释
boost官方文档中聊天程序实例解说 数据包格式chat_message.hpp <pre name="code" class="cpp">< ...
- boost asio异步读写网络聊天程序客户端 实例详解
boost官方文档中聊天程序实例讲解 数据包格式chat_message.hpp <pre name="code" class="cpp">< ...
随机推荐
- 动态规划最短路径LintcodeNO110
动态规划最短路径LintcodeNO110 简单的dp题,没啥好说的... class Solution { public: /** * @param grid: a list of lists of ...
- 剑指Offer-60~68题
60. \(n\) 个骰子的点数 题目描述: 扔 \(n\) 个骰子,向上面的数字之和为 \(S\).给定 \(n\),请列出所有可能的 \(S\) 值及其相应的概率. 示例: 输入:n = 1 输出 ...
- 【Springboot】注解@ConfigurationProperties让配置整齐而简单
1 简介 前面我们用一篇文章<[Spring]只想用一篇文章记录@Value的使用,不想再找其它了(附思维导图)> 详细讲解了在Spring中如何使用@Value来实现我们对配置的需求,它 ...
- cesium加载WFS服务(GeoServer发布)
需求: 为了便于前端渲染数据,自定义图层渲染. 思路: 获取地图服务中的要素进行渲染. 工具: GeoServer 2.6.4,cesium, 思路有了就开始找资料写代码,cesium有接口可以加载W ...
- TensorFlow——训练模型的保存和载入的方法介绍
我们在训练好模型的时候,通常是要将模型进行保存的,以便于下次能够直接的将训练好的模型进行载入. 1.保存模型 首先需要建立一个saver,然后在session中通过saver的save即可将模型保存起 ...
- 为WPF, UWP 及 Xamarin实现一个简单的消息组件
原文地址:Implementing a simple messenger component for WPF, UWP and Xamarin 欢迎大家关注我的公众号:程序员在新西兰了解新西兰IT行业 ...
- dp - 循环数组的最大和
首尾相连数组的最大子数组和 时间限制:1000 ms | 内存限制:65535 KB 难度:4 描述 给定一个由N个整数元素组成的数组arr,数组中有正数也有负数,这个数组不是一般的数组,其首尾是 ...
- mysql高级复习
MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构.可以得到索引的本质:索引是数据结构,可以简单理解为“排好序的快速查找数据结构”. 数据本身之外,数据库还维护着一 ...
- 高校表白app使用体验
在本次软件工程专业交流会中,有幸了解了很多学长学姐研究并且开发的软件,使我受益匪浅.其中最让我记忆犹新的还属一款名为高校表白app的软件.首先这款app的主要功能是为我们提供一个委婉的告白平台,我们可 ...
- get_字段_display()
gender_choices = ((1, '男'), (2, '女')) gender = models.IntegerField(verbose_name='性别', choices=gender ...