学习Linux网络编程基本函数

目录
  • 1,创建套接字socket
    • 函数原型:
    • 参数列表:
    • type的值:
    • protocol得值:
  • 2,绑定套接字bind
    • 函数原型:
    • 参数列表:
  • 3,创建监听;listen
    • 函数原型:
    • 参数列表:
  • 4,等待连接accept
    • 函数原型:
  • 5, 收发消息send和recv
    • 函数原型:
    • 该函数的参数:
    • send的流程:
    • recv的流程:
  • 5,关闭套接字描述符close
    • 函数:
  • 6,基于tcp协议的C/S服务器模型
  • 7,实现代码
    • 服务端:
    • 客户端:

1,创建套接字socket

函数原型:

#include<sys/types.h>
#include<sys/socket.h>
int socket(int domain, int type, int protocol);

参数列表:

domain参数有以下这些值

AF_INET:IPv4协议
AF_INET6:IPv6协议
AF_LOCAL:Unix域协议
AF_ROUTE:路由套接口
AF_KEY:密钥套接口

type的值:

SOCKET_STREAM:双向可靠数据流,对应TCPSOCKET_DGRAM:双向不可靠数据报,对应UDPSOCKET_RAW:提供传输层以下的协议,可以访问内部网络接口,例如接收和发送ICMP报文

protocol得值:

type为SOCKET_RAW时需要设置此值说明协议类型,其他类型设置为0即可

函数的作用是创建一个指定格式的套接字并返回其描述符,成功返回描述符,失败返回-1;

2,绑定套接字bind

函数原型:

#include<sys/types.h>
#include<sys/socket.h>
int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);

参数列表:

sockfd为之前创建的套接字描述符

my_addr是一个通用套接字结构体指针,在做tcp协议编程时通常使用sockaddr_in结构体

该结构体内容如下;

struct socketaddr_in
{
   unsigned short int sin_family;//对应地址族IP v4填AF_INTE
   uint16_t sin_port;//对应端口号
   struct in_addr sin_addr;//对应ip地址
   unsigned char sin_zero[8];
};
struct in_addr
{
   uint32_t s_addr;
};

addrlen为该上述结构体的大小,可以用sizeof求得;

在使用bind函数前需要先创建一个sockaddr_in类型的结构体,将服务器的信息保存到结构体中,

然后将创建的套接字与之绑定;成功返回0,失败返回-1;

在设置端口号和IP时先将结构体清空,如果是主函数传参,那么对应的端口号和ip都是字符串格式,

需要用函数转换,转换格式如下:

char port[]="8888"
char ip[]="192.168.1.1"
struct sockaddr_in seraddr'
seraddr.sin_port=htos(atoi(port))
seraddr.sin_addr.s_addr=inet_addr(ip);

3,创建监听;listen

函数原型:

int listen(int fd, int backlog);

参数列表:

fd为要监听的套接字描述符;backlog为监听队列的大小;

(1) 执行listen 之后套接字进入被动模式。

(2) 队列满了以后,将拒绝新的连接请求。客户端将出现连接D 错误WSAECONNREFUSED。

(3) 在正在listen的套接字上执行listen不起作用。

4,等待连接accept

函数原型:

#include <sys/socket.h>
 int accept(int s, struct sockaddr * addr, int * addrlen);

对比bind函数可以发现两者的参数几乎一样,但是accept中的addr不被const修饰,

也就是说addr是用来保存连接的客户端的地址信息的,同杨addlen时返回的addr的大小;

所以accept函数的作用就是返回已连接的客户端的文件描述符,

并将客户端的地址信息保存在一个新的sockaddr_in结构体中;链接失败返回-1;

5, 收发消息send和recv

函数原型:

  int send( SOCKET s, const char FAR *buf, int len, int flags );
  int recv( SOCKET s, char FAR *buf, int len, int flags); 

该函数的参数:

  • 第一个参数指定发送/接受端套接字描述符;
  • 第二个参数指明一个存放应用程序要发送数据的缓冲区;
  • 第三个参数指明实际要发送/接收的数据的字节数;
  • 第四个参数一般置0。

send的流程:

这里只描述同步Socket的send函数的执行流程。

当调用该函数时,send先比较待发送数据的长度len和套接字s的发送缓冲的长度,

  • 如果len大于s的发送缓冲区的长度,该函数返回SOCKET_ERROR;
  • 如果len小于或者等于s的发送缓冲区的长度,那么send先检查协议是否正在发送s的发送缓冲中的数据,
  • 如果是就等待协议把数据发送完,
  • 如果协议还没有开始发送s的发送缓冲中的数据或者s的发送缓冲中没有数据,那么send就比较s的发送缓冲区的剩余空间和len,
  • 如果len大于剩余空间大小send就一直等待协议把s的发送缓冲中的数据发送完,
  • 如果len小于剩余空间大小send就仅仅把buf中的数据copy到剩余空间里(注意并不是send把s的发送缓冲中的数据传到连接的另一端的,而是协议的,send仅仅是把buf中的数据copy到s的发送缓冲区的剩余空间里);
  • 如果send函数copy数据成功,就返回实际copy的字节数,
  • 如果send在copy数据时出现错误,那么send就返回SOCKET_ERROR;
  • 如果send在等待协议传送数据时网络断开的话,那么send函数也返回SOCKET_ERROR。

要注意send函数把buf中的数据成功copy到s的发送缓冲的剩余空间里后它就返回了,但是此时这些数据并不一定马上被传到连接的另一端。

  • 如果协议在后续的传送过程中出现网络错误的话,那么下一个Socket函数就会返回SOCKET_ERROR。
  • (每一个除send外的Socket函数在执行的最开始总要先等待套接字的发送缓冲中的数据被协议传送完毕才能继续,
  • 如果在等待时出现网络错误,那么该Socket函数就返回SOCKET_ERROR)。

recv的流程:

这里只描述同步Socket的recv函数的执行流程。

当应用程序调用recv函数时,recv先等待s的发送缓冲中的数据被协议传送完毕,

  • 如果协议在传送s的发送缓冲中的数据时出现网络错误,那么recv函数返回SOCKET_ERROR,
  • 如果s的发送缓冲中没有数据或者数据被协议成功发送完毕后,recv先检查套接字s的接收缓冲区,
  • 如果s接收缓冲区中没有数据或者协议正在接收数据,那么recv就一直等待,只到协议把数据接收完毕。
  • 当协议把数据接收完毕,recv函数就把s的接收缓冲中的数据copy到buf中

(注意协议接收到的数据可能大于buf的长度,所以在这种情况下要调用几次recv函数才能把s的接收缓冲中的数据copy完。

recv函数仅仅是copy数据,真正的接收数据是协议来完成的),recv函数返回其实际copy的字节数。

  • 如果recv在copy时出错,那么它返回SOCKET_ERROR;
  • 如果recv函数在等待协议接收数据时网络中断了,那么它返回0。
  • tcp协议本身是可靠的,并不等于应用程序用tcp发送数据就一定是可靠的.
  • 不管是否阻塞,send发送的大小,并不代表对端recv到多少的数据.
  • 在阻塞模式下, send函数的过程是将应用程序请求发送的数据拷贝到发送缓存中发送并得到确认后再返回.

但由于发送缓存的存在,表现为:如果发送缓存大小比请求发送的大小要大,那么send函数立即返回,同时向网络中发送数据;

否则,send向网络发送缓存中不能容纳的那部分数据,并等待对端确认后再返回(接收端只要将数据收到接收缓存中,

就会确认,并不一定要等待应用程序调用recv);

  • 在非阻塞模式下,send函数的过程仅仅是将数据拷贝到协议栈的缓存区而已,
  • 如果缓存区可用空间不够,则尽能力的拷贝,
  • 返回成功拷贝的大小;如缓存区可用空间为0,则返回-1,同时设置errno为EAGAIN.

5,关闭套接字描述符close

函数:

close(sockfd);

和文件操作一样,套接字也是一个文件,使用完之后要关闭;

6,基于tcp协议的C/S服务器模型

图解tcp模型

7,实现代码

服务端:

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>

typedef struct sockaddr_in SIN;
typedef struct sockaddr SA;

int main(int argc,char *argv[])
{
    SIN seraddr;
    SIN cliaddr;
    int len=sizeof(SIN);
    //创建监听套接字
    int lisfd=socket(AF_INET,SOCK_STREAM,0);
    if(lisfd<0)
    {
        perror("socket");
        exit(0);
    }
    printf("创建套接字%d成功\n",lisfd);
    bzero(&seraddr,sizeof(seraddr));
    seraddr.sin_family=AF_INET;
    seraddr.sin_port=htons(8888);
    seraddr.sin_addr.s_addr=inet_addr("192.168.1.6");
    //绑定套接子
    int ret=bind(lisfd,(SA*)(&seraddr),len);
    if(ret<0)
    {
        perror("bind");
        exit(0);
    }
    printf("绑定成功\n");
    //开始监听
    ret=listen(lisfd,1024);
    if(ret<0)
    {
        perror("listen");
        exit(0);
    }
    printf("监听成功\n");
    //等待连接,将连接的套接字信息保存
    int clifd=accept(lisfd,(SA*)(&cliaddr),(socklen_t *)(&len));
    if(clifd<0)
    {
        perror("accept");
        exit(0);
    }
    printf("客户端%d连接成功\n",clifd);
    //读写
    char readbuf[1024]={0};
    char sendbuf[1024]={0};
    while(1)
    {
        recv(clifd,readbuf,sizeof(readbuf),0);
        printf("recv:%s\n",readbuf);
        fgets(sendbuf,sizeof(sendbuf),stdin);
        send(clifd,sendbuf,sizeof(sendbuf),0);
    }
    //关闭套接字
    close(clifd);
    close(lisfd);
    return 0;
}

客户端:

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>

typedef struct sockaddr_in SIN;
typedef struct sockaddr SA;

int main(int argc,char *argv[])
{
    SIN seraddr;
    //创建监听套接字
    int serfd=socket(AF_INET,SOCK_STREAM,0);
    if(serfd<0)
    {
        perror("socket");
        exit(0);
    }
    printf("创建套接字%d成功\n",serfd);
    bzero(&seraddr,sizeof(seraddr));
    seraddr.sin_family=AF_INET;
    seraddr.sin_port=htons(8888);
    seraddr.sin_addr.s_addr=inet_addr("192.168.1.6");
    //请求连接
    int ret=connect(serfd,(SA*)(&seraddr),sizeof(SIN));
    if(ret==-1)
    {
        perror("connect");
        exit(0);
    }
    printf("连接成功\n");
    //读写
    char senbuf[1024]={0};
    char readbuf[1024]={0};
    while(1)
    {
        fgets(senbuf,sizeof(senbuf),stdin);
        send(serfd,senbuf,sizeof(senbuf),0);
        recv(serfd,readbuf,sizeof(readbuf),0);
        printf("recv:%s\n",readbuf);
    }
    //关闭套接字
    close(serfd);
    return 0;
}

以上就是学习Linux网络编程基本函数的详细内容,更多关于Linux网络编程基本函数的资料请关注我们其它相关文章!

(0)

相关推荐

  • Linux网络编程之socket文件传输示例

    本文所述示例程序是基于Linux平台的socket网络编程,实现文件传输功能.该示例是基于TCP流协议实现的socket网络文件传输程序.采用C语言编写.最终能够实现传输任何格式文件的文件传输程序. 具体实现代码如下: Server端代码如下: /************************************************************************* > File Name: Server.c > Author: SongLee ***********

  • Linux网络编程之基于UDP实现可靠的文件传输示例

    了解网络传输协议的人都知道,采用TCP实现文件传输很简单.相对于TCP,由于UDP是面向无连接.不可靠的传输协议,所以我们需要考虑丢包和后发先至(包的顺序)的问题,所以我们想要实现UDP传输文件,则需要解决这两个问题.方法就是给数据包编号,按照包的顺序接收并存储,接收端接收到数据包后发送确认信息给发送端,发送端接收确认数据以后再继续发送下一个包,如果接收端收到的数据包的编号不是期望的编号,则要求发送端重新发送. 下面展示的是基于linux下C语言实现的一个示例程序,该程序定义一个包的结构体,其中

  • linux网络编程用到的网络函数详解用和使用示例

    一.概念介绍网络程序分为服务端程序和客户端程序.服务端即提供服务的一方,客户端为请求服务的一方.但实际情况是有些程序的客户端.服务器端角色不是这么明显,即互为客户端和服务端.我们编写网络程序时,一般是基于TCP协议或者UDP协议进行网络通信的.TCP:(Transfer Control Protocol)传输控制协议是一种面向连接的协议, 当我们的网络程序使用这个协议的时候,网络可以保证我们的客户端和服务端之间的传输是可靠的.UDP:(User Datagram Protocol)用户数据报协议

  • 简析Linux网络编程函数

    目录 1,创建套接字socket 2,绑定套接字bind 3,创建监听:listen 4,等待连接accept 5, 收发消息send和recv 6,关闭套接字描述符close 7,基于tcp协议的C/S服务器模型 8,实现代码 网络编程的一些基本函数:也是实现tcp协议通讯的基本步骤,实现代码在最后,IP需要修改为自己的IP,即可通信: 1,创建套接字socket 函数原型: #include<sys/types.h> #include<sys/socket.h> int soc

  • Linux网络编程之UDP Socket程序示例

    在网络传输协议中,TCP协议提供的是一种可靠的,复杂的,面向连接的数据流(SOCK_STREAM)传输服务,它通过三段式握手过程建立连接.TCP有一种"重传确认"机制,即接收端收到数据后要发出一个肯定确认的信号,发送端如果收到接收端肯定确认的信号,就会继续发送其他的数据,如果没有,它就会重新发送. 相对而言,UDP协议则是一种无连接的,不可靠的数据报(SOCK_DGRAM)传输服务.使用UDP套接口不用建立连接,服务端在调用socket()生成一个套接字并调用bind()绑定端口后就可

  • 学习Linux网络编程基本函数

    目录 1,创建套接字socket 函数原型: 参数列表: type的值: protocol得值: 2,绑定套接字bind 函数原型: 参数列表: 3,创建监听:listen 函数原型: 参数列表: 4,等待连接accept 函数原型: 5, 收发消息send和recv 函数原型: 该函数的参数: send的流程: recv的流程: 5,关闭套接字描述符close 函数: 6,基于tcp协议的C/S服务器模型 7,实现代码 服务端: 客户端: 1,创建套接字socket 函数原型: #includ

  • 谈谈新手如何学习PHP网络编程第1/2页

    文章开头就列举了那么多联系方式,难免会让大家感觉有点AD的意味,但是不容质疑的是,默默的确有那么丁点的表现欲^_^,虽然有时候过于细致会被人说婆妈,但是幸好这种细致对于编程来说,还是蛮有益的! 从默默自己向别人问怎么学PHP开始,到后来不少人又来问默默怎么学PHP,不管默默是新手,还是老鸟,似乎总是感觉摸不出一条清晰的脉络来,不过,默默既然学会了PHP,那么我走的这条路或多或少的有一定借鉴性. PHP的背景恐怕就不用默默赘言了,我相信大家选择一种语言,并不是看它的背景和悠久历史,更重要的是看它的

  • linux 网络编程 socket选项的实现

    socket选项函数 功能:用来读取和设置socket文件描述符属性的方法 #include <sys/scoket.h> int getsockopt ( int sockfd, int level, int option_name, void* option_value, socklen_t* restrict option_len ); int setsockopt ( int sockfd, int level, int option_name, const void* option_

  • C/C++ Linux Socket网络编程流程分析

    目录 一.Socket简介 二.Socket编程基础 1. 网络字节序 2. sockaddr数据结构 3. IP地址转换函数 三.Socket编程函数 1. socket函数 2. bind 函数 3. listen 函数 4. accept 函数 5. connect 函数 6. read 函数 7. write 函数 8. close 函数 四.回声服务器案例 1. 服务器 2. 客户端 3. 运行测试 五.总结 之前已经学习了QT的socket编程 和 C/C++在window环境的so

  • python网络编程学习笔记(二):socket建立网络客户端

    1.建立socket 建立socket对象需要搞清通信类型和协议家族.通信类型指明了用什么协议来传输数据.协议的例子包括IPv4.IPv6.IPX\SPX.AFP.对于internet通信,通信类型基本上都是AF_INET(和IPv4对应).协议家族一般表示TCP通信的SOCK_STREAM或者表示UDP通信的SOCK_DGRAM.因此对于TCP通信,建立一个socket连接的语句为:s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)对于UDP通

  • python网络编程学习笔记(一)

    学习用书:<python 网络编程基础>作者John Goerzen 第一部分底层网络学习 Python提供了访问底层操作系统Socket接口的全部方法,需要的时候这些接口可以提供灵活而强有力的功能. (1)基本客户端操作 在<python 网络编程基础>一书中,作者列出了一个简单的Python客户端程序,具体如下: 复制代码 代码如下: import socket,sysport =70host=sys.argv[1] filename=sys.argv[2] s=socket.

  • 深入学习C#网络编程之HTTP应用编程(下)

    第三篇来的好晚啊,上一篇说了如何向服务器推送信息,这一篇我们看看如何"快好准"的从服务器下拉信息. 网络上有很多大资源文件,比如供人下载的zip包,电影(你懂的),那么我们如何快速的进行下载,大家第一反应肯定就是多线程下载, 那么这些东西是如何做的呢?首先我们可以从"QQ的中转站里面拉一个rar下来". 然后用fiddler监视一下,我们会发现一个有趣的现象: 第一:7.62*1024*1024≈7990914  千真万确是此文件 第二:我明明是一个http链接,t

随机推荐