网络模型

osi 参考模型,tcp/ip 参考模型

网络通讯要素

ip地址,端口号,传输协议

IP地址就是我想找到他的主机地址,但是如何区分是feiq 找他还是qq 找他用端口号区分,每一种进程的端口号是不同的

Socket 编程

浏览器的进程怎么与web服务器通信的,当你用QQ聊天时,QQ进程怎么与服务器或你好友所在的QQ进程通信,这些都得靠socket,那什么是socket?socket的类型有哪些?还有socket的基本函数,进程间通讯要遵循tcp/ip 协议

socket是“open—write/read—close”模式的一种实现

Socket 就是网络服务提供的一种机制,通信的两端都有socket,网络通信其实就是socket 通信,数据在两个socket 间通过io 传输

网络中的进程如何通信

本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类:

消息传递(管道、FIFO、消息队列)

同步(互斥量、条件变量、读写锁、文件和写记录锁、信号量)

共享内存(匿名的和具名的)

远程过程调用(Solaris门和Sun RPC)

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

socket函数对应于普通文件的打开操作。普通文件的打开操作返回一个文件描述字,而socket()用于创建一个socket描述符(socket descriptor),它唯一标识一个socket。这个socket描述字跟文件描述字一样,后续的操作都有用到它,把它作为参数,通过它来进行一些读写操作。

正如可以给fopen的传入不同参数值,以打开不同的文件。创建socket的时候,也可以指定不同的参数创建不同的socket描述符,socket函数的三个参数分别为:

·domain:即协议域,又称为协议族(family)。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。

accept()函数

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

TCP服务器端依次调用socket()、bind()、listen()之后,就会监听指定的socket地址了。TCP客户端依次调用socket()、connect()之后就想TCP服务器发送了一个连接请求。TCP服务器监听到这个请求之后,就会调用accept()函数取接收请求,这样连接就建立好了。之后就可以开始网络I/O操作了,即类同于普通文件的读写I/O操作。

accept函数的第一个参数为服务器的socket描述字,第二个参数为指向struct sockaddr *的指针,用于返回客户端的协议地址,第三个参数为协议地址的长度。如果accpet成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的TCP连接。

注意:accept的第一个参数为服务器的socket描述字,是服务器开始调用socket()函数生成的,称为监听socket描述字;而accept函数返回的是已连接的socket描述字。一个服务器通常通常仅仅只创建一个监听socket描述字,它在该服务器的生命周期内一直存在。内核为每个由服务器进程接受的客户连接创建了一个已连接socket描述字,当服务器完成了对某个客户的服务,相应的已连接socket描述字就被关闭。

read()、write()等函数

万事具备只欠东风,至此服务器与客户已经建立好连接了。可以调用网络I/O进行读写操作了,即实现了网咯中不同进程之间的通信!网络I/O操作有下面几组:read()/write() recv()/send() readv()/writev()recvmsg()/sendmsg()recvfrom()/sendto()其它的我就不一一介绍这几对I/O函数了,具体参见man文档或者baidu、Google,下面的例子中将使用到send/recv。

close()函数

在服务器与客户端建立连接之后,会进行一些读写操作,完成了读写操作就要关闭相应的socket描述字,好比操作完打开的文件要调用fclose关闭打开的文件。

TCP

TCP把连接作为最基本的对象,每一条TCP连接都有两个端点,这种断点我们叫作套接字(socket),它的定义为端口号拼接到IP地址即构成了套接字,例如,若IP地址为192.3.4.16 而端口号为80,那么得到的套接字为192.3.4.16:80。

TCP连接的建立(三次握手)

TCP连接的释放(四次挥手)

为什么客户端最后还要等待2MSL?

MSL(Maximum Segment Lifetime),TCP允许不同的实现可以设置不同的MSL值。
第一,保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。
第二,防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。
为什么建立连接是三次握手,关闭连接确是四次挥手呢?
建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。
而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次。

如果已经建立了连接,但是客户端突然出现故障了怎么办?

TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75分钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

1,tcp分客户端和服务端。2,客户端对应的对象是Socket。服务端对应的对象是ServerSocket。

客户端对应的对象是Socket

/*
客户端,
通过查阅socket对象,发现在该对象建立时,就可以去连接指定主机。
因为tcp是面向连接的。所以在建立socket服务时,
就要有服务端存在,并连接成功。形成通路后,在该通道进行数据的传输。

需求:给服务端发送给一个文本数据。
步骤:
1,创建Socket服务。并指定要连接的主机和端口。
*/
import java.io.*;
import java.net.*;
class  TcpClient
{
    public static void main(String[] args) throws Exception
    {
        //创建客户端的socket服务。指定目的主机和端口
        Socket s = new Socket("192.168.111.1",10003);
        
        //为了发送数据,应该获取socket流中的输出流。
        OutputStream out = s.getOutputStream();
        out.write("tcp ge men lai le ".getBytes());

s.close();
    }
}

如果这个建立了就通了,就有了socket 流

tcp 的服务端对应着多个客户端

一个客户端上面有输入和输出,就像是电话上有听筒和话筒,打电话的人是这边的话筒对应着那一面的听筒,那边的话筒对应着这的听筒,在当客户端和服务端建立连接以后,服务端会得到客户端的对象,同样客户端对象都会存在输入和 输出,客户端的输入对应着服务端的客户端对象的输出,客户端的输出对应着服务端的客户端对象的输入。

服务端对应的对象是ServerSocket

/*
需求:定义端点接收数据并打印在控制台上。
服务端:
1 建立服务端的socket服务。ServerSocket();
    并监听一个端口。
2  获取连接过来的客户端对象。
    通过ServerSokcet的 accept方法。没有连接就会等,所以这个方法阻塞式的。
3,客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据。
    并打印在控制台。
4,关闭服务端。(可选)

*/
class  TcpServer
{
    public static void main(String[] args) throws Exception
    {
        //建立服务端socket服务。并监听一个端口。
        ServerSocket ss = new ServerSocket(10003);
        //通过accept方法获取连接过来的客户端对象。
        while(true)
        {
        Socket s = ss.accept();
        String ip = s.getInetAddress().getHostAddress();
        System.out.println(ip+".....connected");
        //获取客户端发送过来的数据,那么要使用客户端对象的读取流来读取数据。
        InputStream in = s.getInputStream();
        
        byte[] buf = new byte[1024];
        int len = in.read(buf);
        System.out.println(new String(buf,0,len));
        s.close();//关闭客户端.//取完了数据就把你断开,要不
        }
        //ss.close();
    }
}

serverSocket 只能在dos 命令下运行

所以不能在eclipse 中运行

在dos 命令下运行的时候把里面的注释文字删除

把这两个文件拷贝过来

先启动服务端,在启动客户端

然后服务端就会出现

udp

DatagramSocket 既能发送又能接收,数据包就是DatagramPacket,建立发送端和接收端,用完socket 要进行关闭,发送端和接收端是 两个独立运行的程序。

由于udp 是面向无连接的

需求:通过udp传输方式,将一段文字数据发送出去。

定义一个udp发送端。

思路:

1,建立udpsocket服务。

2,提供数据,并将数据封装到数据包中。

3,通过socket服务的发送功能,将数据包发出去。

4,关闭资源。

class UdpSend {

public static void main(String[] args) throws Exception {

//1,创建udp服务。通过DatagramSocket对象。

DatagramSocket ds = new DatagramSocket(8888);//8888 就是设置自己的端口号是8888

//2,确定数据,并封装成数据包。

DatagramPacket(byte[] buf, int length, InetAddress address, int port)

byte[] buf = "udp ge men lai le ".getBytes();

// 192.168.111.1 表示的当前电脑的ip 地址

// 表示的是把数据发送到192.168.111.1 这个10000端口上,表示把数据包从8888端口发送到10000端口

DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.111.1"),10000);

//3,通过socket服务,将已有的数据包发送出去。通过send方法。ds.send(dp);//4,关闭资源。ds.close();}}

如果这样直接运行数据就丢失了

需求: 定义一个应用程序,用于接收udp协议传输的数据并处理的。

定义udp的接收端。

思路: 1,定义udpsocket服务。通常会监听一个端口。其实就是给这个接收网络应用程序定义数字标识。 方便于明确哪些数据过来该应用程序可以处理。

2,定义一个数据包,因为要存储接收到的字节数据。 因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。

3,通过socket服务的receive方法将收到的数据存入已定义好的数据包中。

4,通过数据包对象的特有功能。将这些不同的数据取出。打印在控制台上。

5,关闭资源。

class UdpRece {

public static void main(String[] args) throws Exception {

//1,创建udp socket,建立端点。

DatagramSocket ds = new DatagramSocket(10000); //10000表示的接收来自于10000端口的数据

while(true) { //2,定义数据包。用于存储数据。

byte[] buf = new byte[1024];

DatagramPacket dp = new DatagramPacket(buf,buf.length);

//3,通过服务的receive方法将收到数据存入数据包中。

ds.receive(dp);//阻塞式方法。

//4,通过数据包的方法获取其中的数据。

String ip = dp.getAddress().getHostAddress();

String data = new String(dp.getData(),0,dp.getLength());

int port = dp.getPort();

ystem.out.println(ip+"::"+data+"::"+port); }

//5,关闭资源

//ds.close(); } }

//10000表示的接收来自于10000端口的数据

while(true) {

//2,定义数据包。用于存储数据。

byte[] buf = new byte[1024];

DatagramPacket dp = new DatagramPacket(buf,buf.length);

//3,通过服务的receive方法将收到数据存入数据包中。

ds.receive(dp);//阻塞式方法。

//4,通过数据包的方法获取其中的数据。

String ip = dp.getAddress().getHostAddress();

String data = new String(dp.getData(),0,dp.getLength());

int port = dp.getPort(); System.out.println(ip+"::"+data+"::"+port); }

//5,关闭资源 //ds.close(); } }

DatagramSocket 既能发送又能接收,数据包就是DatagramPacket,建立发送端和接收端,用完socket 要进行关闭,发送端和接收端是 两个独立运行的程序。

运行结果:

实例一:

操作过程是首先运行udpRece 但是运行这个文件的时候没有什么反应,主要是 ds.receive(dp);//阻塞式方法,就是一直等待发送端有数据了为准,如果没有数据就一直等待,然后运行发送端

加上while(true)的原因就是一直等待发送端发过来的数据,并且接收端取消了资源关闭,就是资源一直是开着的,这样导致的结果就是接收端不用关闭,发送端那边只要改了值直接一运行就可以了

 

 

实例二:

UDP 键盘录入

接收端的代码就是上面的代码,发送端发生了变化,采用的是键盘录入的方式

先运行receive 端

udpsend2 端进行的,回车以后

实例三:

/*
编写一个聊天程序。
有收数据的部分,和发数据的部分。
这两部分需要同时执行。
那就需要用到多线程技术。
一个线程控制收,一个线程控制发。
因为收和发动作是不一致的,所以要定义两个run方法。
而且这两个方法要封装到不同的类中。
*/
import java.io.*;
import java.net.*;
class Send implements Runnable
{
    private DatagramSocket ds;
    public Send(DatagramSocket ds)
    {
        this.ds = ds;
    }

public void run()
    {
        try
        {
            BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
            String line = null;
            while((line=bufr.readLine())!=null)
            {
                
                byte[] buf = line.getBytes();
                DatagramPacket dp =
                    new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.255"),10002);
                ds.send(dp);
                if("886".equals(line))
                    break;
            }
        }
        catch (Exception e)
        {
            throw new RuntimeException("发送端失败");
        }
    }
}
class Rece implements Runnable
{
    private DatagramSocket ds;
    public Rece(DatagramSocket ds)
    {
        this.ds = ds;
    }
    public void run()
    {
        try
        {
            while(true)
            {
                byte[] buf = new byte[1024];
                DatagramPacket dp = new DatagramPacket(buf,buf.length);
                ds.receive(dp);
                String ip = dp.getAddress().getHostAddress();
                String data = new String(dp.getData(),0,dp.getLength());
                if("886".equals(data))
                {
                    System.out.println(ip+"....离开聊天室");
                    break;
                }
                System.out.println(ip+":"+data);
            }
        }
        catch (Exception e)
        {
            throw new RuntimeException("接收端失败");
        }
    }
}

class  ChatDemo
{
    public static void main(String[] args) throws Exception
    {
        DatagramSocket sendSocket = new DatagramSocket();
        DatagramSocket receSocket = new DatagramSocket(10002);
        new Thread(new Send(sendSocket)).start();
        new Thread(new Rece(receSocket)).start();
    }
}

运行一下主函数就启动了两个线程

就是这样一种感觉

其实聊天室就是在同一个界面的,其实道理和开两个窗口是一样的

socket 编程基础相关推荐

  1. Java从零开始学四十五(Socket编程基础)

    一.网络编程中两个主要的问题 一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输. 在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可 ...

  2. 你得学会并且学得会的Socket编程基础知识

    这一篇文章,我将图文并茂地介绍Socket编程的基础知识,我相信,如果你按照步骤做完实验,一定可以对Socket编程有更好地理解. 本文源代码,可以通过这里下载 http://files.cnblog ...

  3. 【转】Java Socket编程基础及深入讲解

    原文:https://www.cnblogs.com/yiwangzhibujian/p/7107785.html#q2.3.3 Socket是Java网络编程的基础,了解还是有好处的, 这篇文章主要 ...

  4. Python学习笔记——基础篇【第七周】———FTP作业(面向对象编程进阶 Socket编程基础)...

    FTP作业 本节内容: 面向对象高级语法部分 Socket开发基础 作业:开发一个支持多用户在线的FTP程序 面向对象高级语法部分 参考:http://www.cnblogs.com/wupeiqi/ ...

  5. java socket 重连复用_Java Socket编程基础及深入讲解(示例代码)

    Socket是Java网络编程的基础,了解还是有好处的, 这篇文章主要讲解Socket的基础编程.Socket用在哪呢,主要用在进程间,网络间通信.本篇比较长,特别做了个目录: 一.Socket通信基 ...

  6. 你得学会并且学得会的Socket编程基础知识(转)

    这一篇文章,我将图文并茂地介绍Socket编程的基础知识,我相信,如果你按照步骤做完实验,一定可以对Socket编程有更好地理解. 本文源代码,可以通过这里下载 http://files.cnblog ...

  7. socket编程基础知识

    一.预备知识 1.理解源IP和目的IP 因特网上的每台计算机都有一个唯一的IP地址,如果一台主机上的数据要通过网络传输到另一台主机,那么对端主机的IP地址就应该作为该数据传输时的目的IP地址.但仅仅知 ...

  8. 初识网络及socket编程基础

    理解源IP地址和目的IP地址 在IP数据包头部中, 有两个IP地址, 分别叫做源IP地址, 和目的IP地址. 源ip地址就是发送端ip,目的ip地址就是接收端ip 思考: 我们光有IP地址就可以完成通 ...

  9. Python Socket编程基础篇

    Socket网络编程 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. ...

最新文章

  1. 一篇了解NLP中的注意力机制
  2. @ParameterizedTest在@CvsSource中具有空值
  3. PHPStorm开启Debug
  4. 欧式距离、曼哈顿距离、余弦相似度(python代码)
  5. Effective C# Item33:限制类型的可见性
  6. TutorialsPoint 电子书 归档 2017
  7. 阿里巴巴数据报告:消费向境内回流 低线城市消费蓬勃
  8. C/C++ 文件读写操作总结
  9. 电脑不启动任务管理器时cpu使用率很高,短时间内不使用电脑时启动为什么能耗可下降到15%以下?
  10. VS2012写的程序在VS2010打开时显示当前版本不兼容
  11. MySQL面试题中:主从同步部署介绍
  12. 永中云编辑(java版)
  13. GEO、TCGA数据下载慢 下载中断解决办法
  14. Y的十年职业生涯小结(2012-2022)
  15. 【内网穿透笔记】FTP映射出现227 Entering Passive Mode错误命令原因及解决方法
  16. 小喵的VUE项目搭建(一)
  17. MATLAB NAR时间序列神经网络两种预测方法
  18. Java中模拟评分系统_评分系统.java
  19. windows10 插入耳机无弹出,无声音,提示扬声器、耳机未插入
  20. 【hadoop权威指南第四版】第七章MR的类型与格式【笔记+代码】

热门文章

  1. 旅行商问题(travelling salesman problem, TSP) 解题报告
  2. 服务器安装octopus-非root用户
  3. Centos7快速单机搭建ceph(Octopus版)
  4. 基于ARM Cortex-A8和Android 4.x的联动报警系统 (Android 、A8、Linux、驱动、NDK)
  5. 微软 Windows 10 v2004 最新官方 ISO 镜像
  6. 资源网站合集 五个值得你收藏的网站
  7. 【RMAN】数据库备份之冷备份
  8. Tim Sweeney 采访实录:Metaverse的商业规则该如何打造?
  9. el-upload上传失败提示框重新上传直接弹出选择文件
  10. P44 单行子查询案例分析