socket应用编程实验(一)

Socket应用编程实验(1)

  • Socket简介

  • HTTP/HTTPS协议

  • Socket编程实验

    Socket API

  • BSD Socket API

    • 不是为每个应用程序定义接口,而是提供最基本的通信功能

    • 对上层提供统一的调用接口,支持丰富的上层应用开发

      //=====================BSD Socket API=======================
      socket(domain,type,proto);
      close(sockfd);
      bind(sockfd,addr,addrlen);
      //=============Datagram(Connectionless)======================
      sendto(sockfd,buf,len,flags,dest_aaddr,addrlen);
      recvfrom(sockfd,buf,len,flags,src_addr,addrlen);
      //=============Stream(Connection-oriented)===================
      listen(sockfd,backlog);
      accept(sockfd,addr,&addrlen);
      connect(sockfd,addr,addren);
      send(sockfd,buf,len,flags);
      recv(sockfd,&buf,len,flags);
      
  • Socket调用流程

在这里插入图片描述

一、建立socket文件描述符

  • 数据收发两端都需要建立socket文件描述符

    # include<sys/socket.h>
    int socket(int domain,int type,int protocol);
    
    //在Linux 下使用<sys/socket.h>头文件中的socket()函数来创建套接字,原型为
    int socket(int af,int type,int protocol);
    
    1) af为地址族(Address Family),也就是IP地址类型,常用的有 AF_INET 和AF_INET6。
    AF是"address Family"的简写,INET是"Inetnet"的简写。AF_INET表示IPv4地址,例如
    127.0.0.1;AF_INET6表示IPv6地址,例如 1030::C9B4:FF12:48AA:1A2B.
    
    127.0.0.1是一个特殊的IP地址,表示本机地址
        
    
    2) type为数据传输方式/套接字类型,常用的有 SOCK_STREAM (流格式套接字/面向连接的套接字)SOCK_DGRAM (数据报套接字/无连接的套接字)3) protocol 表示传输协议,常用的有 IPPROTO_TCP 和 IPPTOTO_UDP, 分别表示 TCP 传输协议和 UDP传输协议。
    
     int socket(IP地址类型(IPv4/IPv6), 数据传输方式(SOCK_STREAM / SOCK_DGRAM), 传输协议(IPPROTO_TCP/IPPTOTO_UDP))
    
    • 第三个参数,一般情况下有了af 和 type 两个参数就可以创建套接字了,操作系统会自动推演出协议类型,除非遇到: 有两种不同的协议支持同一种地址类型和数据传输类型。如果不指明,操作系统无法自动推演。

      /* 使用IPv4地址,参数af的值为 AF_INET ,如果使用 SOCK_STREAM 传输数据,那么满足
      这两个条件的协议只有 TCP,因此可以这样调用 socket()函数:  */
      int tcp_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
      /* 使用SOCK_DRGAM 传输方式,满足这两个条件的协议只有 UDP*/
      int udp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
      /* 上面两种情况都只有一种协议满足条件,可以将 protocol 的值设为0,系统会自动推演出应该使用什么协议 */
      int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);	// 创建TCP套接字
      int udp_socket = socket(AF_INET, SOCK_DRGAM, 0);	// 创建UDP套接字
      
      • Domain: AF_INET

      • Type

        • SOCK_STREAM TCP

        • SOCK_DGRAM UDP

          • Protocol: 0

          • 返回值: socket 文件描述符

            int sockfd = socket(AF_INET, SOCK_STREAM, 0);
            

        二、将socket文件描述符与监听地址绑定

    bind()函数功能

    将 address 指向的 sockaddr 结构体中描述的一些属性(IP地址、端口号、地址簇) 与 socket套接字绑定,也叫给套接字命名

    调用bind()后,就为 sockfd 套接字关联了一个相应的地址与端口号,即发送到该地址该端口的数据可以通过 sockfd 读取和使用。当然也可通过该 sockfd 发送数据到指定目的。

    对于 Server, bind()是必须要做的事情,服务器启动时需要绑定指定的端口来提供服务(以便于客户向指定的端口发送请求),对于服务器 sockfd 绑定地址,一般而言将 IP 地址复制为 INADDR_ANY(该宏值为 0),即无论发送到系统中的哪个 IP 地址(当服务器有多张网卡时会有多个 IP 地址)的请求都采用该 sockfd 来处理,而无需指定固定 IP。

    对于 Client , 一般而言无需主动调用 bind(),一切由操作系统来完成。在发送数据前,操作系统会为套接字随机分配一个可用的端口,同时将该套接字和本地地址信息绑定。

    • 只需要被动建立连接一方进行绑定(bind)

      int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
      sockfd : Socket 文件描述符
      addr :  需要绑定的地址和端口
      addrlen : 地址和端口数据结构的长度
      
    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(80);  // 主机字节序调整为网络字节序,80端口是http协议
    
    bind(sockfd,(struct sockaddr *)&server, sizeof(server));
    

三、进行监听

  • 只在被动建立连接一方进行监听,等待新的连接请求

    int listen(int sockfd, int backlog)
     // backlog 指最多允许多少个客户连接到服务器,它的值至少为1。收到连接请求后,这些请求需要排队,如果队列满,就拒绝请求。
    
  • sockfd: 之前建立的文件描述符

  • backlog: 可以理解为待处理请求的最大数目

    listen(sockfd,128);
    

四、接受连接请求

accept() 接收一个套接字中已建立的连接

# include<sys/types.h>
# include<sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • 功能参数描述

accept()系统调用主要用在基于连接的套接字类型 ,比如 SOCK_STREAM 和 SOCK_SEQPACKET。**它提取出所监听套接字的等待连接队列中第一个连接请求,创建一个新的套接字,并返回指向该套接字的文件描述符。**新建立的套接字不在监听状态,原来所监听的套接字也不受该系统调用的影响。新建立的套接字准备发送send()和接收数据recv()。

  • 参数

  • sockfd, 利用系统调用socket()建立的套接字描述符,通过bind()绑定到一个本地地址(一般为服务器的套接字),并且通过listen()一直在监听连接。

  • addr : 指向struct sockaddr 的指针,该结构用**通讯层服务器对等套接字的地址(一般为客户端地址)**填写,返回地址 addr 的确切格式由套接字的地址类别(比如TCP或者UDP)决定;若addr为NULL,没有有效地址填写,这种情况下,addrlen也不使用,应该置为 NULL;

    addr 是个指向局部数据结构 sockaddr_in 的指针,这就是要求接入的信息本地的套接字(地址和指针)。

  • addrlen: 一个值结果参数,调用函数必须初始化为包含 addr 所指向结构大小的数值,函数返回时包含对等地址(一般为服务器地址)的实际数值;

    addrlen 是个局部整型变量,设置为sizeof(struct sockaddr_in)

    如果队列中没有等待的连接,套接字也没有被标记为Non-blocking,accept()会阻塞调用函数直到连接出现; 如果套接字被标记为 Non-blocking,队列中也没有等待的连接, accept()返回错误

    EAGAIN 或 WWOULDBLOCK。

    • 一般来说,实现时 accept()为阻塞函数,当监听sockfd 调用 accept()时,它先到自己的 receive_buf 中查看是否有连接数据包;
    • 若有,把数据拷贝出来,删掉接收到的数据包,创建新的socket 与客户发来的地址建立连接;
    • 若没有,就阻塞等待;

​ 为了在套接字中有到来的连接时得到通知,可以使用select() 或 poll() 。当尝试建立新连接时,系统发送一个可读事件,然后调用accept()为该连接获取套接字。另一种方法是,当套接字中有连接到来时设定套接字发送SIGIO信号。

  • 返回值:成功:返回非负整数,该整数是接收到套接字的描述符;出错返回-1,相应设定全局变量errno。

    被动建立连接一方需要显式的接收连接请求
     int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    sockfd: 之前建立的 socket文件描述符
    addr : 用于存储对端网络地址的数据结构
    addrlen : 指定 addr 大小
    返回值为该连接对应的文件描述符,以后收发数据都使用该文件描述符:
    int csock = accept(sockfd, (struct sockaddr_in *)&caddr, &clen);
    
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实验报告 实验Socket编程 一、实验目的 通过socket程序的编写、调试,掌握socket编程的基本方法,了解客户端与服务器端的特点,掌握并熟悉运用socket类与ServerSocket类。 实验内容 学习socket编程使用的类和接口,着重掌握基于TCP协议的socket。 编写服务器端的应用程序 编写客户端的应用程序 实现服务器端与客户端的交互 实验代码 1.服务器端程序 过程:在端口5000上创建一个等待连接的ServerSocket对象server:server=new ServerSocket(5000);接着调用server对象的accept()方法等待某客户程序发出连接请求。该方法一直阻塞直到有客户连接到带端口。一旦有客户发送正确请求,则连接成功,accept()方法返回一个Socket对象,于是得到了一个新的用于通信的Socket对象,通信链路建立成功。然后利用Socket类提供的方法创建Socket对象的输入流和输出流。此后即于客户端进行通信,直到客户端断开连接即关闭各个流结束通信。 代码如下: import java.net.*; import java.io.*; class aa { static public void main (String args[]) throws IOException { ServerSocket server=null; Socket socket=null; InputStream is=null; OutputStream os=null; DataInputStream in=null; PrintStream out=null; try Socket编程实验报告全文共6页,当前为第1页。 { //在端口5000注册服务 Socket编程实验报告全文共6页,当前为第1页。 server=new ServerSocket(5000); socket =server.accept();//侦听连接请求,等待连接 System.out.println("**********************服务器端界面*************************"); System.out.println("与客户端连接成功!"); System.out.println(""); System.out.println("对话内容为:"); System.out.println(""); System.out.println("等待客户发送信息....."); //获取对应的Socket的输入/输出流 is=socket.getInputStream(); os=socket.getOutputStream(); //建立数据流 in= new DataInputStream(is); out =new PrintStream(os);//表示向对方输出 out.println("Welcome!");//表示向对方输出 String str=in.readLine();//逐行读取 do { System.out.println("客户端说:"+ str); str=in.readLine(); }while(str.trim().equals("BYE")) //如果是"BYE"就退出 System.out.println("客户想要离开"); } catch(Exception e) //捕获程序异常 { System.out.println("Error:"+e); } finally { is.close();//关闭输入流 os.close();//关闭输出流 in.close();//关闭数据输入流 socket.close();//关闭socket } } } 2.客户端程序 过程:首先创建一个指向服务器的指定端口号(5000)的Socket对象socketsocket=new Socket("localhost",5000);此时服务器指定为本地计算机,若要在网络中指定服务器,只需要将参数localhost改成相应的服务器名或者IP地址即可。 然后程序利用Socket类提供的方法创建Socket对象的输入流和输出流。此后即于服务器通信,断开连接即关闭各个流结束通信。 Socket编程实验报告全文共6页,当前为第2页。代码如下: Socket编程实验报告全文共6页,当前为第2页。 import java.net.*; import java.io.*; class bb { static public void main (String args[]) throws IOException { Socket socket=null; Input

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值