1.Socket 定义

套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。网络套接字是IP地址与端口的组合。

传输层实现端到端的通信,因此,每一个传输层连接由两个端点/。那么,传输层连接的断电是什么呢,不是主机,不是主机的IP地址,不是应用进程,也不是传输层的协议端口,传输层连接的端点叫做套接字(socket)。根据RFC793的定义,端口号拼接到IP地址就构成了套接字。所谓套接字,实际上是一个通信端点,每个套接字都有一个套接字序号,包括主机的IP地址与一个16为的主机端口号,即形如(主机IP地址:端口号)。例如,如果IP地址是210.37.145.1,而端口号是23,那么得到套接字就是(210.37.145.1:23).总之,套接字Socket=(IP地址:端口号),套接字的表示方法是点分十进制的IP地址后面写上端口号,中间用冒号或逗号隔开。每一个传输层链接唯一地被通信两端的两个端点(即两个套接字)所确定。

2. Hello/Hi

下面用Java简单的实现一个基于Socket通信的hello/hi程序:

Server端:

importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.PrintWriter;importjava.net.ServerSocket;importjava.net.Socket;importjava.util.Scanner;classServer {privateSocket server;privateServer() {try{

System.out.println("启动服务器!");

ServerSocket serverSocket= new ServerSocket(8888);

server=serverSocket.accept();

}catch(IOException e) {

e.printStackTrace();

}

}private voidlisten() {try{

System.out.println("Listening!......");//从Socket中获得输入流

InputStreamReader in = newInputStreamReader(server.getInputStream());

BufferedReader br= newBufferedReader(in);//读取输入流中的一行并输出

System.out.println(br.readLine());

}catch(IOException e) {

e.printStackTrace();

}

}private voidsend(String msg) {try{

PrintWriter out= new PrintWriter(server.getOutputStream(), true);

out.println("Server:" +msg);

}catch(IOException e) {

e.printStackTrace();

}

}public static voidmain(String[] args) {

Server se= newServer();

String msg= "";

Scanner cin= newScanner(System.in);while (!msg.equals("#")) {

se.listen();

System.out.print("输入信息:");

msg=cin.nextLine();

se.send(msg);

}

}

}

Client端:

importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.PrintWriter;importjava.net.Socket;importjava.util.Scanner;classClient {privateSocket client;privateClient() {try{

client= new Socket("127.0.0.1", 8888);

}catch(Exception e) {

e.printStackTrace();

}

}private voidsend(String msg) {try{

PrintWriter out= new PrintWriter(client.getOutputStream(), true);

out.println("Client:" +msg);

}catch(IOException e) {

e.printStackTrace();

}

}private voidlisten() {try{

System.out.println("Listening!......");

InputStreamReader in= newInputStreamReader(client.getInputStream());

BufferedReader br= newBufferedReader(in);

System.out.println(br.readLine());

}catch(IOException e) {

e.printStackTrace();

}

}public static voidmain(String[] args) {

String msg= "";

Client c= newClient();

Scanner cin= newScanner(System.in);while (!msg.equals("#")) {

System.out.print("Input: ");

msg=cin.nextLine();

c.send(msg);

c.listen();

}

}

}

执行结果:

Client发送hello,Server回应hi

调用栈分析:

为什么java实现socket通信这么方便呢,这就需要我们深入源码去一探究竟了,这里以Server端为例,追踪调用栈:

实例化ServerSocket时,构造函数会调用ServerSocket的bind()方法,

public ServerSocket(int port, int backlog, InetAddress bindAddr) throwsIOException {

...if (port >= 0 && port <= 65535) {if (backlog < 1) {

backlog= 50;

}try{this.bind(newInetSocketAddress(bindAddr, port), backlog);

}catch(SecurityException var5) {this.close();throwvar5;

}catch(IOException var6) {this.close();throwvar6;

}

}else{throw new IllegalArgumentException("Port value out of range: " +port);

}

}

public void bind(SocketAddress endpoint, int backlog) throwsIOException {

...try{

SecurityManager security=System.getSecurityManager();if (security != null) {

security.checkListen(epoint.getPort());

}this.getImpl().bind(epoint.getAddress(), epoint.getPort());this.getImpl().listen(backlog);this.bound = true;

}catch(SecurityException var5) {this.bound = false;throwvar5;

}catch(IOException var6) {this.bound = false;throwvar6;

}

...

}

该方法会调用继承自抽象类AbstractPlainSocketImpl的PlainSocketImpl的socketBind()方法,在该方法中会调用native方法bind0(),从而实现将一个socket连接绑定到指定的本地IP地址和端口号。

注:native关键字标注的方法为本地方法,一般是用其他语言写成的函数,常用来实现java语言对OS底层接口的访问。Java语言本身不能直接对操作系统底层进行操作,但是java允许程序通过Java本机接口JNI,使用C/C++等其他语言实现这种操作。在Windows系统中,使用native关键字标注的本地方法在编译时会生成一个动态链接库(.dll文件)为Java语言提供响应的本地服务。

void socketBind(InetAddress address, int port) throwsIOException {int nativefd = this.checkAndReturnNativeFD();if (address == null) {throw new NullPointerException("inet address argument is null.");

}else if (preferIPv4Stack && !(address instanceofInet4Address)) {throw new SocketException("Protocol family not supported");

}else{

bind0(nativefd, address, port, useExclusiveBind);if (port == 0) {this.localport =localPort0(nativefd);

}else{this.localport =port;

}this.address =address;

}

}

接着,同样的步骤从ServerSocket的listen()方法可以一直追溯到PlainSocketImpl的sokectListen()方法的listen0(),该方法主要为了设置允许的最大连接请求队列长度,当请求队列满时,拒绝后来的连接请求。

最后,同样,从ServerSocket类的accept()追溯到accept0(),等待连接请求的到来。

3. Java Socekt API与Linux Socket API对比

Linux提供的响应Socket API在sys/socket.h中,分别为:

int socket(int domain, int type, intprotocol);

从函数名就可以看出,socket函数可以创建一个socket,

其中,domain参数告诉系统使用哪个底层协议族,对TCP/IP协议族而言,该参数应该设置为PF_INET或PF_INET6,没错,分别对应IPv4和IPv6,对于UNIX本地域协议族而言,该参数应该设置为PF_UNIX,具体socket系统支持的所有协议族,请读者自行参考其man手册。

type参数指定服务类型,主要有SOCK_STREAM流服务和SOCK_UGRAM数据报服务,对TCP/IP协议族而言,其值取SOCK_STREAM表示传输层使用TCP协议,取SOCK_DGRAM表示传输层使用UDP协议。

protocol参数是在前两个参数构成的协议集合下,再选择一个具体的协议。不过这个值通常是唯一的,几乎在所有情况下,我们都应该把它设置为0,表示使用默认协议。

熟悉UNIX/Linux的同学应该知道,在这类系统中,所有的东西都是文件,socket也不例外,可读,可写,可控制,可关闭的文件描述符。socket函数调用成功时返回一个socket文件描述符

int bind(int sockfd, const struct sockaddr *addr, socklen_t addelen)

bind将my_addr所指的socket地址分配给未命名的socketfd文件描述符,addrlen参数指出该socket地址的长度。bind成功时返回0,失败则返回-1并设置errno,常见为EACCES和EASSRINUSE,前者代表被绑定的地址是受保护的地址,仅超级用户能够访问,后者表示被绑定的地址正在使用中。

值得注意的是,Client端通常不需要bind socket而是采用匿名方式,OS自动分配socket地址。

int listen(int sockfd, int backlog);

socket被bind之后还不能马上接收客户的连接,需要创建一个监听队列存放待处理的客户连接,服务端通过listen进行监听。

sockfd参数指定被监听的socket,backlog参数体时内核监听队列的最大长度,如果超过,服务器将不再受理新的客户端连接,客户端也将收到ECONNREFUSED错误信息。listen成功返回0,失败返回-1并设置errno。

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

最后一步为accept,其中sockfd参数是执行过listen系统调用的监听socket,addr参数用来获取被接受连接的远程socket地址,该socket地址的长度由addlen参数指出,accpet成功时返回一个新的连接socket,该socket唯一地标识了被接受的这个连接,服务器可通过读写该socket来与被接受连接对应的客户端通信,accept失败时返回-1并设置errno。

其实,Java也是调用Linux网络API实现网络通信的,通过调用这些系统API来实现它的底层功能的,从调用分析时贴出的源码中可以看出,在Java的ServerSocket创建时就对方法进行了socket的bind和listen操作,一个方法就封装了3个API,即ServerSocket的实例化过程就对应了Linux中的socket(),bind(),listen(),而Java中的accept对应了Linux的accept函数,相关对应关系如下图所示(图来源https://blog.csdn.net/vipshop_fin_dev/article/details/102966081):

所以,Java将这一切全都封装起来,这使得面向网络的编程对于Java程序员来说变得十分简单,我们只需要知道使用的哪一个类(实际上也就是ServerSocket和Socket两个类),为它们传入必要的地址参数,就能够轻松实现Socket通信。

api有哪些 javasocket_简单hello/hi程序、分析及Java Socket API与Linux Socket API对比相关推荐

  1. 简单网络聊天程序java_基于Java实现hello/hi简单网络聊天程序

    Socket简要阐述 Socket的概念 Socket的英文原义是"孔"或"插座". 在网络编程中,网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连 ...

  2. 一个简单的木马程序分析

    目录 Mini木马的基本原理 Mini木马介绍 实验环境 系统环境 开发环境 木马实现 进行实验 辅助工具telnet的安装 虚拟机运行木马 本机与虚拟机创建连接 主机对虚拟机进行操作 查看当前用户 ...

  3. 用Java编写一个最简单的桌面程序

    使用Java的优势在于网络应用方面,但Java也提供了强大的用于开发桌面程序的API,它们包含在javax.swing包中.使用这个包可以编写简单的Java桌面应用程序. Java的javax.swi ...

  4. 基于时间片轮转程序分析进程调度

    张雨梅   原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-10000 背景知识 一般程序运行过程中都 ...

  5. api有哪些 javasocket_Java Socket编程以及与Linux Socket API关系

    Socket 编程(基于Linux) Socket独立于具体协议的网络编程接口,在ISO模型中,主要位于会话层和传输层之间:在通用的计算机网络五层模型中,主要位于应用层和传输层之间. Linux So ...

  6. 线程模型、pthread 系列函数 和 简单多线程服务器端程序

    一.线程有3种模型,分别是N:1用户线程模型,1:1核心线程模型和N:M混合线程模型,posix thread属于1:1模型. (一).N:1用户线程模型 "线程实现"建立在&qu ...

  7. java可视化日历_Java简单可视化日历程序

    涉及知识: 一.Date类 在JDK1.0中,Date类是唯一的一个代表时间的类,但是由于Date类不便于实现国际化,所以从JDK1.1版本开始,推荐使用Calendar类进行时间和日期处理.这里简单 ...

  8. Android 简单基站定位程序

    原帖地址:http://www.cnblogs.com/rayee/archive/2012/02/02/2336101.html 声明 本系列文章不是教程,仅为笔记,如有不当之处请指正. 欢迎转载, ...

  9. 深入浅出WPF(2)——解剖最简单的GUI程序

    深入浅出WPF(2)--解剖最简单的GUI程序 小序: 从这篇文章开始,我们进行XAML语言的上手学习.说实话,XAML这种语言一点也不难.如果把XML看成是"父类",那么XAML ...

最新文章

  1. Java笔记:成员变量,局部变量,类变量,实例变量以及注意事项
  2. 用shell写了一个自动编译代码的脚本
  3. CodeForces - 1339C Powered Addition(思维+贪心)
  4. 无人值守的自动 dump(二)
  5. 【OpenPose-Windows】中断问题及图像不同分辨率对帧率的影响
  6. Redis 究竟适不适合当队列来用?
  7. maven工程打包老是报错_maven工程pom文件老是报错
  8. 大屏数据可视化源码_AxureBI数据大屏可视化原型设计软件
  9. 忘记root密码后怎么解决?克隆虚拟机后如何实现两台linux相互登录?
  10. zai php 里面写js,php中写入js代码
  11. 12个从小到超级成功的博客案例研究
  12. 骁龙855音频解码芯片_小米10、小10 Pro详细对比:骁龙865最强悍5G旗舰手机
  13. python ar_四种AR的实现方式
  14. 【深度学习】DCGAN实现动漫头像生成详细说明
  15. python 导出到excel ,打开excel有错误,错误的提示为:发现“***”中的部分内容问题,是否让我们尽量尝试修复?如果您信任此工作簿的源,请单击“是”。
  16. Android中如何利用Minui显示PNG格式的图片
  17. 使用python调用nmap模块实现端口扫描
  18. 计算机基础-将机械硬盘换成固态硬盘
  19. java中static什么意思_Java中static的含义和用法
  20. AES密钥编排Python实现

热门文章

  1. [数据库] mysql
  2. 一篇讲解iphone6 双核处理器的新闻稿
  3. Android : Broadcast
  4. Python Matplotlib绘制多子图准备训练数据和GIF动画实践
  5. Linux服务器下Matlab的安装
  6. 如何完美解决解决win10系统--无法自动修复此计算机问题
  7. VS2019字符编码设置
  8. MySQL理论基础以及sql语法
  9. 蚂蚁金服 Service Mesh 深度实践
  10. 解决-笔记本安装CentOS 7 后无法连接Wi-Fi