前言:该博客花了我一个下午得心血,全部手打,路过给个赞,拒绝抄袭!!!!!!!!!!!!!!!!!!!!!!!!!

简单的SOCKET通信程序

先从一段简单的JAVA程序性开始写起,这里我们才用半双工的形式,这里的半双工意思是客户端可以给服务端发送数据,发完数据就关闭,而服务端可以一直接受数据

我们使用多线程方式,这个不重要

下面是线程类

  1. public class SocketThread implements Runnable {
  2. public SocketThread(Socket socket) {
  3. this.socket = socket;
  4. }
  5.  
  6. private Socket socket;
  7. @Override
  8. public void run() {
  9. InputStream inputStream = null;
  10. InputStreamReader inputStreamReader = null;
  11. BufferedReader bufferedReader = null;
  12. try {
  13. inputStream = socket.getInputStream();
  14. inputStreamReader = new InputStreamReader(inputStream);
  15. bufferedReader = new BufferedReader(inputStreamReader);
  16. char buf[] = new char[1024];
  17. int len=0;
  18. while ((len=bufferedReader.read(buf))!=-1){
  19. for(int i=0;i<len;i++){
  20. System.out.print(buf[i]);
  21. }
  22. System.out.println();
  23. }
  24. }catch (Exception e){
  25. e.printStackTrace();
  26. }finally {
  27. try {
  28. inputStream.close();
  29. inputStreamReader.close();
  30. bufferedReader.close();
  31. } catch (IOException e) {
  32. e.printStackTrace();
  33. }
  34. }
  35. }
  36. }

说实话,这个博客园的博客丑的一B,为什么不能提交CSDN的博客呢?

服务端代码:

  1. public class Server {
  2. public static void main(String[] args) {
  3. try{
  4. ServerSocket serverSocket = new ServerSocket(8888);
  5. System.out.println("服务端已启动,等待连接");
  6. while(true){
  7. Socket socket = serverSocket.accept();
  8. SocketThread socketThread = new SocketThread(socket);
  9. new Thread(socketThread).start();
  10. }
  11. }catch (Exception e){
  12. e.printStackTrace();
  13. }
  14. }
  15. }

客户端代码:

  1. public class Client {
  2. public static void main(String[] args) {
  3. try {
  4. Socket socket = new Socket("localhost",8888);
  5. OutputStream outputStream = socket.getOutputStream();
  6. Scanner scan = new Scanner(System.in);
  7. while(scan.hasNext()){
  8. String str = scan.next();
  9. outputStream.write(str.getBytes());
  10. outputStream.flush();
  11. }
  12. }catch (Exception e){
  13. e.printStackTrace();
  14. }
  15. }
  16. }

分析

想要搞明白JAVA和LINUX之间的关系,首先你得明白我们的java代码编译成class文件后是运行在JVM上,这个CLASS字节码文件只有我们JVM认识,你扔给操作系统,操作系统铁定不懂。

JVM也是一个软件,它是由C++和C编写的,我们姑且认为它是C编写的,相信大家都看过JAVA源码,太多方法都是调用了native方法,比如我们的bind()方法

其次,JAVA的很多功能都是通过调用操作系统函数来实现的,比如显示文字

JAVA比如建立Socket是通过告诉虚拟机这个指令,然后虚拟机调用操作系统的Socket()函数来实现的

查看一下LINUX的SOCKET函数

简单说一下,第一个参数是域类型,看到IPV4选它就完事了,第二个参数是协议,我们用SOCK_STRAM表示TCP协议,第三个取0,0会把前两个参数对应起来,写0就完事了

return value是返回一个文件描述符,这个很难明白,你可以把它理解为我们JAVA里面的对象,JAVA当中有句话叫一切皆对象,而在LINUX中相应的我们叫做一切皆文件

只要我们拿到这个文件描述符,就能操作相应的Socket,牛逼吧= =

好的,下面讲一下验证思路

我们写一个JAVA方法,这个方法也调用NATVIE方法,而这个方法就不是JVM提供的C了,而是我们自己写的一个C文件,用这个C文件的函数调用操作系统内核函数来建立Socket连接,这里的StartServer()

方法就相当于我们之前的ServerSocket socket = new ServerSocket();如果能调用成功,是不是说明JAVA就是通过调用LINUX函数实现的呢?

正篇开始

先放代码

在我们JAVA中有socket.bind(),在C语言中怎么写呢?也是一样的,调用bind()函数即可,我们也来瞧瞧

第一个字段就是把我们刚刚的文件描述符传过来,第二个就比较复杂了我的哥,在C语言中我们的参数非常复杂,传入参数,传出参数和传入传出参数

啥意思?其实很简单,传入参数就是传进来修改不会影响外面,类似局部变量,。。。传入传出就是指针啥的嘛,我们这里就是结构体指针,但是如果加了一个const就不一样

const 意思是我们不能修改它即只能传入,不能传出

这个sockaddr 结构体里面有两个参数,一个是IP,一个是端口号PORT,就是IP+端口,最后是你结构体的长度

看正篇最开始的代码,为什么我这里写的是sockaddr_in呢?参数不是sockaddr嘛?你可以把这个理解为JAVA当中的类型,人家要一个INT结果你传一个字符串

这个其实是在UNIX开发之初,我们的IP协议还没有很稳定的时候是用sockaddr来描述的,但是随着计算机的发展,IP协议越来越复杂,所以它开发了另一个函数叫Sockaddr_in来表示我们的IP和端口号,所以这个方法已经过时了,但是为什么没改掉呢?这个很简单啊,和JAVA一样它在很多地方都有使用,你不能随便改,就像JAVA一样我们都是声明接口,传入实现类等等保障系统的可扩展性。那怎么办?其实很简单,我们传一个参数进来然后把它强转成这个类型不就好了

这个htons是啥?这个叫本地转换成网络字节数,短整型,说白了,你这个8080人家LINUX不认识,你需要通过转换。比如你传一个192.168.。。。人家LINUX不认识,它需要把它转换成123456的整形才认识,这就是提供转换的函数

INADDR_ANY是啥,你也可以换成localhost,这里表示当前本机任何一个可用的IP地址

这个listen是监听你当前Socket当中在同一时刻能够接受的连接数,它默认值是128,无所谓,他不是关键

这是啥?传出来的是C语言类型的数据,不是我们能看懂的IP等,我们需要转换一下,就转到这个数组中

这个就是读数据啊,读到这个字符串数据里,以及它的长度

关键

这里涉及JNI调用,不懂得自己去看吧。关于什么是JNI我就不解释了

首先来段简单代码,这个conn()会调用到我们自己写得C方法,注意你的包名设置,等会编译的时候需要你到你LINUX目录的上一级目录编译 com.类名

把这个JAVA文件拷贝到LINUX系统里

然后编译这个java文件成.h文件,这里注意你的JDK环境设置,我一开始用的是OPEN JDK是没有JAVAC命令的

关键来了,我们查看我们编译好的.h文件

然后这个.h文件可以在我们写的函数里导入进来那我们那个方法怎么命名,参考.h文件,这个.h中生成了一个conn()方法的C语言调用连接

这个JNIEXPORT。。。就是我们得调用函数名称,替换C文件得方法名即可

你可以把这个方法看成conn()方法在LINUX下的名称,等会调用conn()方法等于调用这个方法

注意一下,你必须指定你的classpath路径,否则我们得java System.loadLibray是找不到得,很简单得道理,你写JAVA得时候你在当前目录下得文件,你要JAVA怎么运行呢?

还有就是必须导入/include和/include/linux下的两个头文件,参考我上面的命令

哈哈哈,可以看到我们运行JAVA已经调用到LINUX下得内核函数了,下面来测试一哈

牛逼吹完了,看看效果

这个nc是用来模拟连接得,可以直接通信了,哈哈哈

证明成功!

总结:好累啊,再也不想这么认真写实验了= =。写了一个下午,我要去划水

JAVA网络通信底层调用LINUX探究的更多相关文章

  1. 如何在java程序中调用linux命令或者shell脚本

    转自:http://blog.sina.com.cn/s/blog_6433391301019bpn.html 在java程序中如何调用linux的命令?如何调用shell脚本呢? 这里不得不提到ja ...

  2. java程序中调用Linux命令Windows命令

    目前总结的方法: 调用Linux简单的命令行,设置文件夹权限755 String scriptDir = "/home/wenf"; String cmd = "chmo ...

  3. JAVA Socket API与LINUX Socket API探究

    代码 这是一个带有UI界面的JAVA网络聊天程序,使用Socket连接完成通信. JAVA服务端程序 import java.io.IOException; import java.io.InputS ...

  4. java调用Linux命令报错:java.io.IOException: Cannot run program "ps": CreateProcess error=2, ?????????

    在idea里面,java代码:Runtime.getRuntime().exec("ps -aux") 是因为默认是用windows平台运行了,所以报错,得改成调用Linux平台运 ...

  5. java远程调用linux的命令或者脚本

    转载自:http://eksliang.iteye.com/blog/2105862 Java通过SSH2协议执行远程Shell脚本(ganymed-ssh2-build210.jar) 使用步骤如下 ...

  6. java调用Linux执行Python爬虫,并将数据存储到elasticsearch--(环境脚本搭建)

    java调用Linux执行Python爬虫,并将数据存储到elasticsearch中 一.以下博客代码使用的开发工具及环境如下: 1.idea: 2.jdk:1.8 3.elasticsearch: ...

  7. Java调用Linux命令(cd的处理)

    一.Java调用Linux系统的命令非常简单 这是一个非常常用的调用方法示例: public String executeLinuxCmd(String cmd) { System.out.print ...

  8. java调用linux下的so库

    1.编写java类 public class Abc { static { System.loadLibrary("abc"); } public native static St ...

  9. Java调用Linux命令执行

    调用方式 Java调用linux命令执行的方式有两种,一种是直接调用linux命令,一种是将linux命令写到.sh脚本中,然后调用脚本执行. 详细说明 直接调用:使用java中lang包下面的Run ...

随机推荐

  1. The command ("dfs.browser.action.delete") is undefined 解决Hadoop Eclipse插件报错

    Hadoop Eclipse插件 报错. 使用 hadoop-eclipse-kepler-plugin-2.2.0.jar 如下所示 Error Log 强迫症看了 受不了 The command ...

  2. react框架安装和使用

    react 其实react跟vue差不多, 区别:vue-  双向数据绑定, react  单向数据绑定. 中文文档:https://react.docschina.org/ 第一步:安装方式,不能直 ...

  3. Python的深浅拷贝

    Python的深浅拷贝 深浅拷贝 1. 赋值,对于list, set, dict来说, 直接赋值. 其实是把内存地址交给变量并不是复制一份内容 list1 = [']] list2 = list1 p ...

  4. 超融合与传统IT架构对比:成本价格优势有哪些

    之前文章中,我们已经介绍了超融合给用户 IT 基础架构带来的各个方面的价值,其中成本只是超融合架构的优势之一.但很多用户还是会非常关心这个话题,希望能有更具体的了解,所以本文整理超融合和传统 FC S ...

  5. AQS 入门

    一 AQS简介 路径:java.util.concurrent.locks.AbstractOwnableSynchronizer. 定义:AQS提供了一种 通过维护一个volatile修饰 int类 ...

  6. Nginx 的请求处理流程,你了解吗?

    之前我们已经讲解了 Nginx 的基础内容,接下来我们开始介绍 Nginx 的架构基础. 为什么我们要讨论 Nginx 的架构基础? 因为 Nginx 运行在企业内网的最外层也就是边缘节点,那么他处理 ...

  7. 「刷题」GERALD07加强版

    是LCT了. 首先我们不知道联通块怎么数. 然后颓标签知道了是LCT. 那么考虑一下怎么LCT搞. 有一个很普遍的思路大家也应该都知道,就是如何求一个区间中某种颜色的个数. 这个可以很简单的用主席树来 ...

  8. CSPS模拟 57

    rank4大众rank T1 天空龙 让他自由翱翔吧 T2 巨神兵 对于n=10的测试点本可以打出非常优秀的分层状压 但是没有打出来,因为对拓扑图理解不够深刻,纠结于指回的边,实际上只关注伸出的边就可 ...

  9. 爬虫之request库主要解析---参照慕课北理工嵩天

    kv = {'key1':'value1','key2':'value2'} r = requests.request (' GET' , 'http://python123.io/ws' , par ...

  10. linux shell中使用sed命令

    例1:批量的将变量的值代替指定文件中的指定内容. #!/bin/bash for i in {1..100} mgr_port=`expr $i + 5345` data_port=`expr $i ...