unix网络编程-简易服务器与客户端程序解析

这篇具有很好参考价值的文章主要介绍了unix网络编程-简易服务器与客户端程序解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1 常用缩写

a -- address

f -- file        eg: fputs() -- file put stream

fd -- file descriptor

h - host(主机)

in/inet -- internet        eg: sockaddr_in; inet_aton

n -- network(网络字节序)/numeric(数值)

p -- protocol(协议)/presentation(表达/呈现形式)

s -- socket        eg: sin -- socket internet

t -- type,用于指定某种类型,很多情况下无特殊含义

u -- unsigned(无符号)        eg: uint16 -- unsigned int 16 bits

2 常见类型

SA -- struct sockaddr -- 通用套接字地址结构

socklen_t,套接字地址结构长度,一般为uint32_t

sa_family_t,在支持长度字段(sin_len)中是8位无符号整型,不支持则是16位

in_addr_t, ipv4地址,至少32位的无符号整型,一般为uint32_t

in_port_t, tcp/udp端口,至少16位的无符号整型一般为unit16_t

3 套接字与套接字函数

套接字(socket)是一种通信端点,用于在网络中进行数据传输。在网络编程中,套接字是一个抽象的概念,通常用于创建、配置和管理网络连接。套接字负责处理网络通信的细节,包括建立连接、传输数据和断开连接等

套接字函数是在网络编程中常用的一类函数,用于创建、管理和操作套接字,实现网络通信。套接字函数以引用的形式传递套接字地址结构,相应的参数是一个指向套接字地址结构的指针。

进程到内核的套接字函数:bind(), connect(), sendto()

内核到进程的套接字函数:accept(), recvfrom(), getsockname(), getpeername()

关于进程和内核在本文不做进一步探讨。

4 套接字地址结构

POSIX:可移植操作系统接口(Portable Operating System Interface of UNIX),是由IEEE定义的一系列标准

前文提到,大多数套接字函数需要一个指向套接字地址结构的指针,而这些结构的名字均以sockaddr_开头。下列套接字结构均采用POSIX定义:

4.1 ipv4套接字地址结构sockaddr_in

struct in_addr
{
    in_addr_t s_addr;        //uint32_t,表示ipv4地址
                             //t是一个无明确含义的后缀
                             //网络字节序
};

struct sockaddr_in           //标*为POSIX规范必要字段
{
    uint8_t sin_len;         //长度字段,16字节
    sa_family_t sin_family;  //*协议族,AF_INET4
    in_port_t sin_port;      //*uint16_t,表示端口号
    struct in_addr sin_addr; //*上面已定义
    char sin_zero[8];        //未使用,零填充
};

4.2 通用套接字地址结构sockaddr/SA

struct sockaddr         //对指向特定协议的sa结构进行强制类型转换
{
    unit8_t sa_len;     
    sa_family_t sa_family;
    char sa_data[14];   //与特定协议相关的地址信息
};

4.3 ipv6套接字地址结构sockaddr_in6

struct in6_addr
{
    uint8_t s6_addr[16];        //128bit,表示ipv6地址
                                //网络字节序
};
#define SIN6_LEN
struct sockaddr_in6      
{
    uint8_t sin6_len;           //长度字段,28字节
    sa_family_t sin6_family;    //协议族,AF_INET6
    in_port_t sin6_port;        //网络字节序,表示端口号
    uint32_t sin6_flowinfo;     //流信息,通常置0
    struct in6_addr sin6_addr;  //上面已定义
    uint32_t sin6_scope_id;     //标识接口的范围
};

5 字节操纵函数

 在处理套接字地址结构时,对字节进行处理的函数

5.1 以b(byte)开头的

void bzero(void *dest, size_t nbytes);
void bcopy(const void *src, void *dest, sieze_t btypes);
int bcmp(const void *ptrl, const void *ptr2, size_t nbytes);

bzero:把dest字符串中nbytes个字节置0,用于初始化套接字地址结构

bcopy:将btypes个字节从src原地址移到dest目的地址

bcmp:比较两个字符串,相同则返回0,不同返回非0

5.2 以mem(memory)开头的

void *memset(void *dest, int c, size_t len);
void *memcpy(void *dest, const void *src, size_t nbytes);
void memcmp(const void *ptrl, const void *ptrl2, size_t nbytes);

memset:把dest字符串中len个字节置为c

memcpy:与bcopy类似,但先目的地址再源地址,与赋值语句的顺序一致

memcmp:比较两个字符串,相同则返回0,ptrl1比ptrl2大则返回正数(想必大家c语言都学过)

6 地址转换函数

6.1. 地址字符串与网络字节序二进制值的转换

int inet_aton(const char *strptr, struct in_addr *addrptr);

inet_aton:有效返回1,无效返回0

in_addr_t inet_addr(const char *strptr);

 inet_addr:有效则返回32位二进制网络字节序的ipv4地址,否则返回INADDR_NONE

char *inet_ntoa(struct in_addr inaddr);

 inet_ntoa:返回一个点分十进制的指针

6.2 表达(ASCII字符串)与数值(二进制值)的转换

int inet_pton(int family, const char *strptr, void *addrptr);

inet_pton:有效返回1,无效返回-1

const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);

inet_ntop:有效返回指针,否则返回NULL

7 时间获取程序

7.1 一个简单的客户端程序(ipv4/ipv6)

#include "unp.h"
int main(int argc, char **argv) 
{
    
    int sockfd; 
    //创建文件描述符,返回一个整型来唯一标识一个打开的文件
    int n;  
    //是read函数的返回值,代表从套接字中读取到的字节数
    char recvline[MAXLINE + 1]; 
    //确保数组可以容纳最大长度为MAXLINE的字符串,并在末尾存储终止符\0
    struct sockaddr_in servaddr;     //ipv4  
    //struct sockaddr_in6 servaddr;  //ipv6 
    //创建套接字表示服务器IPv4/ipv6端口号和地址

    if (argc != 2)  //如果命令行输入的参数数量不是2,则出错
        err_quit("usage: a.out <IPaddress>");

    if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
    //if ( (sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0)【ipv6】 
        err_sys("socket error");
    //socket函数三个参数代表ipv4,面向连接的tcp套接字
    //0表示使用默认的协议,对tcp来说通常是0
    //返回值sockfd若为-1则创建套接字失败
    //这两行代码可以用包裹函数Socket()等效代替,如后文服务器代码中所示

    bzero(&servaddr, sizeof(servaddr)); 
    //将从起始位置到sizeof()大小的内存区域置0,可用下面的代码代替
    // memset(&servaddr, 0, sizeof(servaddr));

    servaddr.sin_family = AF_INET;      //地址族为ipv4
    //servaddr.sin6_family = AF_INET6;  //地址族为ipv6 

    servaddr.sin_port = htons(13);  
    //servaddr.sin6_port = htons(13);【ipv6】 
    //用sin_port来存储端口号,这里为网络字节序中的13
    //用htons()将主机字节序(可能是大端或者小端)转换为网络字节序(大端)

    if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) 
    //if (inet_pton(AF_INET6, argv[1], &servaddr.sin6_addr) <= 0)【ipv6】    
        err_quit("inet_pton error for %s", argv[1]);
    //用inet_pton()将第二个命令行参数(ip地址)转换为二进制
    //并存储在seraddr.sin_addr中

    if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)    
        err_sys("connect error");
    //建立一个连接到远程服务器的套接字连接
    //SA即为struct sockaddr通用套接字

    while ( (n = read(sockfd, recvline, MAXLINE)) > 0)  
    {
        recvline[n] = 0;    //把末尾数据清零
        if (fputs(recvline, stdout) == EOF) 
            err_sys("fputs error");
        //将从服务器读取的数据写入标准输出流(stdout)
        //fputs返回非负数则成功,返回负数代表错误(End Of File)
    }
    //从套接字中读取至多MAXLINE个字,
    //若n等于0则读到了文件末尾
    if(n<0)
        err_sys("read error");
    exit(0);
}

7.2 一个简单的服务器程序(ipv4)

看完客户端代码,服务器代码也就大同小异了

#include	"unp.h"
#include	<time.h>

int
main(int argc, char **argv)
{
	int					listenfd, connfd;
	struct sockaddr_in	servaddr;
	char				buff[MAXLINE];
	time_t				ticks;

	
	listenfd = Socket(AF_INET, SOCK_STREAM, 0);
	//用listen()转化为监听套接字,ipv4,tcp	
    //将套接字函数的首字母大写,则变成了对应的具有错误检测功能的包裹函数
	bzero(&servaddr, sizeof(servaddr));
	//将从起始位置到sizeof()大小的内存区域置0
	servaddr.sin_family      = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	//指定ip地址为INADDR_ANY,即能在任意网络接口上监听客户连接
	servaddr.sin_port        = htons(13);	/* daytime server */

	Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
	//将监听套接字绑定到服务器地址上
	//izeof(servaddr)表示要绑定的地址信息的长度
	Listen(listenfd, LISTENQ);
	//LISTENQ:常数,表示系统内核允许在这排队的最大客户连接数

	for ( ; ; )  //无限循环
	{
		connfd = Accept(listenfd, (SA *) NULL, NULL);
		//Accept:阻塞函数,当没有连接请求的时候会一直等待
		//(SA*) NULL:表示不获取客户端的地址信息
		//NULL:表示不获取客户端地址的地址长度参数
		//confid:接受Accept返回的套接字文件描述符
        ticks = time(NULL);
		//获取当前时间,并将当前秒数返回给ticks
        snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
		//格式化输出,写入buff这个指定的缓冲区
        Write(connfd, buff, strlen(buff));
		//向已建立连接的文件描述符connfd写入数据
		Close(connfd);
	}
}

 至此,对这个简单的客户端和服务器程序应该有了较为全面的理解。文章来源地址https://www.toymoban.com/news/detail-794571.html

到了这里,关于unix网络编程-简易服务器与客户端程序解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 网络编程(一)TCP单进程服务器编程详解

    想要学习socket网络编程的读者一定要首先学好计算机网络的理论知识,包括 1)osi网络七层模型与ip四层模型 2)套接字含义 3)局域网通信过程 4)广域网通信过程 5)tcp,udp通信协议,在这两个协议中的连接建立,数据封装,传输过程,传输中可能遇到的问题的处理(差错控

    2024年02月15日
    浏览(32)
  • 【网络编程】demo版TCP网络服务器实现

    UDP和TCP的区别: 对于TCP协议有几个特点: 1️⃣ 传输层协议 2️⃣ 有连接(正式通信前要先建立连接) 3️⃣ 可靠传输(在内部帮我们做可靠传输工作) 4️⃣ 面向字节流 对于UDP协议有几个特点: 1️⃣ 传输层协议 2️⃣ 无连接 3️⃣ 不可靠传输 4️⃣ 面向数据报 可以看到

    2024年02月06日
    浏览(40)
  • 【网络编程】demo版UDP网络服务器实现

    在上一章【网络编程】socket套接字中我们讲述了TCP/UDP协议,这一篇就是简单实现一个UDP协议的网络服务器。 我们也讲过其实 网络通信的本质就是进程间通信 。而进程间通信无非就是读和写(IO)。 所以现在我们就要写一个服务端(server)接收数据,客户端(client)发送数据

    2024年02月02日
    浏览(35)
  • 网络编程: 服务器百万连接实现

    实验内容: 用三个客户端与服务器建立百万连接 服务器代码: Reactor 将实验遇到的问题记录如下 一个TCP连接叫做TCP控制块(tcp control block)。区分网络连接的五元组元素有 添加功能 增加服务器监听端口 如果服务器只用一个端口,那么至少需要10e6/(2^16-1024) ≈ 16台虚拟机。(能分

    2024年01月20日
    浏览(34)
  • Java 网络编程 —— 创建多线程服务器

    一个典型的单线程服务器示例如下: 服务端接收到一个客户连接,就与客户进行通信,通信完毕后断开连接,然后接收下一个客户连接,假如同时有多个客户连接请求这些客户就必须排队等候。如果长时间让客户等待,就会使网站失去信誉,从而降低访问量。 一般用并发性

    2024年02月02日
    浏览(34)
  • 网络编程 lesson6 服务器模型和网络超时检测

    目录 服务器模型介绍 网络编程服务器模型 循环服务器模型 并发服务器模型 1. 多线程服务器 2. 多进程服务器 3. 事件驱动服务器 网络超时检测 应用场景 设置超时检测的方式 1.利用函数参数设置 代码示例 2.利用socket属性设置 3.利用alarm定时器设置 代码示例 在网络模型中,服

    2024年02月06日
    浏览(29)
  • linux并发服务器 —— linux网络编程(七)

    C/S结构 - 客户机/服务器;采用两层结构,服务器负责数据的管理,客户机负责完成与用户的交互;C/S结构中,服务器 - 后台服务,客户机 - 前台功能; 优点 1. 充分发挥客户端PC处理能力,先在客户端处理再提交服务器,响应速度快; 2. 操作界面好看,满足个性化需求; 3.

    2024年02月09日
    浏览(59)
  • 网络编程六--UDP服务器客户端

    UDP(User Datagram Protocol)称为用户数据报协议,是一种无连接的传输协议。 UDP的主要应用在即使丢失部分数据,也不影响整体效果的场景。例实时传输视频或音频时,即使丢失部分数据,也不会影响整体效果,只是会有轻微的画面抖动或杂音。 UDP服务器/客户端不像TCP那样,交

    2024年02月15日
    浏览(34)
  • 【网络编程】高性能并发服务器源码剖析

      hello !大家好呀! 欢迎大家来到我的网络编程系列之洪水网络攻击,在这篇文章中, 你将会学习到在网络编程中如何搭建一个高性能的并发服务器,并且我会给出源码进行剖析,以及手绘UML图来帮助大家来理解,希望能让大家更能了解网络编程技术!!! 希望这篇文章能

    2024年04月15日
    浏览(33)
  • 【skynet】 网络编程之回显服务器

    skynet 提供了一套 tcp 的 API ,本文将给出简单的回显服务器实现,以及讲解。 拉取 skynet 工程 编译 负责启动 gate 服务 \\\"L\\\" 表示客服端的消息前带四字节大端序的 msg_size skynet.address(skynet.self()) 把自己设置为 watchdog ,有新连接通过 text 消息告诉自己 port TCP 监听端口 0 将 TCP 数据

    2024年04月25日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包