Linux应用程序设计之网络基础编程
1、TCP/IP协议概述
1.1、OSI参考模型及TCP/IP参考模型

1.2、TCP/IP协议族

1.3、TCP和UDP
1、TCP
(2)三次握手协议

(3)TCP数据报头

2、UDP

3、协议的选择
4、网络基础编程
4.1、socket概述
1、socket定义
2、socket类型
sockaddr和sockaddr_in两个结构体用来保存socket的信息,如下所示:
struct sockaddr {
unsigned short sa_family;/*地址族*/
char sa_data[14];/*14字节的协议地址,包含该socket的IP地址和端口*/
}; struct sockaddr_in {
short nt sa_family;/*地址族*/
unsigned short int sin_port;/*端口号*/
struct in_addr sin_addr;/*IP地址*/
unsigned char sin_zero[8];/*填充0以保持与struct sockaddr同样大小*/
};
| 结构头文件 | #include |
| sa_family | AF_INET:IPv4协议 |
| AF_INET6:IPv6协议 | |
| AF_LOCAL:UNIX域协议 | |
| AF_LINK:链路地址协议 | |
| AF_KEY:密钥套接字(socket) |
| 所需头文件 |
#include
|
| 函数原型 |
uint16_t htons(uint16_t host16bit)
uint32_t htonl(uint16_t host32bit)
uint16_t ntohs(uint16_t net16bit)
uint16_t ntohl(uint16_t net32bit)
|
| 参数 | host16bit:主机字节序的16bit数据 |
| host32bit:主机字节序的32bit数据 | |
|
net16bit:网络字节序的16bit数据
|
|
| net32bit:网络字节序的32bit数据 | |
| 返回值 | 成功:返回要转换的字节 |
| 失败:-1 |
| 所需头文件 | #include |
| 函数原型 | int inet_pton(int family,const char *strptr, void *addrptr) |
| 参数 | family: AF_INET:IPv4协议;AF_INET6:IPv6协议 |
| strptr:要转化的值 | |
| addrptr:转化后的地址 | |
| 返回值 | 成功:0 |
| 失败:-1 |
| 所需头文件 | #include |
| 函数原型 | int inet_ntop(int family,void *addrptr, char *strptr, size_t len) |
| 参数 | family: AF_INET:IPv4协议;AF_INET6:IPv6协议 |
| strptr:要转化的值 | |
| addrptr:转化后的地址;len:转化后值得大小 | |
| 返回值 | 成功:0 |
| 失败:-1 |
struct hostent {
char *h_name;/*正式主机名*/
char **h_aliases;/*主机别名*/
int h_addrtype;/*地址类型*/
int h_length;/*地址长度*/
char **h_addr_list;/*指向IPv4或IPv6的地址指针数组*/
};调用该函数后就能返回hostent结构体的相关信息。
getaddrinfo函数涉及到一个addrinfo结构体,如下:
struct addrinfo{
int ai_flags;/*AI_PASSIVE,A_CANONNAME*/
int ai_family;/*地址族*/
int ai_socktype;/*socket类型*/
int ai_protocol;/*协议类型*/
size_t ai_addrlen;/*地址长度*/
char *ai_canoname;/*主机名*/
struct sockaddr *ai_addr;/socket结构体/
struct addrinfo *ai_next;/*下一个指针链表*/
}
| 所需头文件 | #include |
| 函数原型 | struct hostent *gethostbyname(const char *hostname) |
| 参数 | hostname :主机名 |
| 返回值 | 成功:hostent类型指针 |
| 失败:-1 |
| 头文件 | #include |
| 函数原型 | int getaddringo(const *hostname,const char *service,const struct addrinfo *hints,struct addrinfo **result) |
| 参数 | hostname:主机名 |
| service:服务名或十进制的串口字符串 | |
| hints:服务线索 | |
| result:返回结果 | |
| 返回值 | 成功:0 |
| 失败:-1 |
| 结构体头文件 | |
| ai_flags | AI_PASSIVE:该套接口是用作被动的打开 |
| AI_CANONNAME:通知getaddrinfo函数返回主机名字 | |
| family | AF_INET:IPv协议 |
| AF_INET6:IPv6协议 | |
| AF_UNSPE:IPv4或IPv6均可: | |
| ai_socktype | SOCK_STREAM:字节流套接字socket(TCP) |
|
SOCK_DGRAM:数据报套接字socket(UDP)
|
|
| ai_protocol | IPPROTO_IP:IP协议 |
| IPPROTO_IPV4:IPv4协议 | |
| IPPROTO_IPV6:IPv6协议 | |
| IPPROTO_UDP:UDP协议 | |
| IPPROTO_TCP:TCP协议 |
/*getaddrinfo.c*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h> int main()
{
struct addrinfo hints, *res = NULL; int rc;
memset(&hints,0,sizeof(hints)); /*设置addrinfo结构体各参数*/ hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP; /*调用getaddrinfo函数*/ rc = getaddrinfo("127.0.0.1","123",&hints,&res);
if(rc != 0)
{
perror("getaddrinfo");
exit(1);
} else
printf("getaddrinfo success\n"); }
4.3、socket基础编程


| 所需头文件 | #include | |
| 函数原型 | int socket(int family, int type, int protocol) | |
| 参数 |
family:
协议族
|
AF_INET:IPv4协议 |
| AF_INET6:IPv6协议 | ||
| AF_LOCAL:UNIX域协议 | ||
| AF_ROUTE:路由套接字 | ||
| AF_KEY:密钥套接字 | ||
|
type:
套接字类型
|
SOCK_STREAM:字节流套接字 | |
| SOCK_DGRAM:数据报套接字 | ||
| SOCK_RAW:原始套接字 | ||
| protocol:0(原始套接字除外) | ||
| 返回值 | 成功:非负套接字描述符 | |
| 失败:-1 | ||
| 所需头文件 | #include |
| 函数原型 | int bind(int sockfd,struct sockaddr *my_addr, int addrlen) |
| 参数原型 | sockfd:套接字描述符 |
| my_addr:本地地址 | |
| addrlen:地址长度 | |
| 返回值 | 成功:0 |
| 失败:-1 |
| 所需头文件 | #include |
| 函数原型 | int listen(int socket, int backlog) |
| 参数原型 | sockfd:套接字描述符 |
| backlog:请求队列中允许的最大请求数,大多数系统缺省值为20 | |
| 返回值 | 成功:0 |
| 失败:-1 |
| 所需头文件 | #include |
| 函数原型 | int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen) |
| 参数 | sockfd:套接字描述符 |
| addr:客户端地址 | |
| addrlen:地址长度 | |
| 返回值 | 成功:0 |
| 失败:-1 |
| 所需头文件 | #include |
| 函数原型 | int connect(int sockfd,struct sockaddr *serv_addr,int addrlen) |
| 参数 | sockfd:套接字描述符 |
| serv_add:服务器地址 | |
| addrlen:地址长度 | |
| 返回值 | 成功:0 |
| 失败:-1 |
| 所需头文件 | #include |
| 函数原型 | int send(int sockfd, const void *msg, int len, int flags) |
| 参数 | sockfd:套接字描述符 |
| msg:指向发送数据的指针 | |
| len:数据长度 | |
| flags:一般为0 | |
| 返回值 | 成功:发送的字节数 |
| 失败:-1 |
| 所需头文件 | #include |
| 函数原型 | int recv(int sockfd, void *buf, int len, unsigned int flags) |
| 参数 |
sockfd:套接字 描述符
|
| buf:存放接收数据的缓冲区 | |
| len:数据长度 | |
| flags:一般为0 | |
| 返回值 | 成功:接收的字节数 |
| 失败:-1 |
| 所需头文件 | #include |
| 函数原型 | int sendto(int sockfd, const void *msg,int len ,unsigned int flags,const struct sockaddr *to, int tolen) |
| 参数 | soctfd:套接字描述符 |
| msg:指向要发送数据的指针 | |
| len:数据长度 | |
| flags:一般为0 | |
| to:目的机的IP地址和端口信息 | |
| tolen:地址长度 | |
| 返回值 | 成功:发送的字节数 |
| 失败:-1 |
| 所需头文件 | #include |
| 函数原型 | int recvfrom(int sockfd, void *buf,int len, unsigned int flags,struct sockaddr *from,int *fromlen) |
| 参数 | sockfd:套接字描述符 |
| buf:存放接收数据的缓冲区 | |
| len:数据长度 | |
| flags:一般为0 | |
| from:源机的IP地址和端口号信息 | |
| fromto:地址长度 | |
| 返回值 | 成功:接收的字节数 |
| 失败:-1 |
/*server.c*/
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#define SERVPORT 3333
#define BACKLOG 10
#define MAX_CONNECTED_NO 10
#define MAXDATASIZE 5
int main()
{
struct sockaddr_in server_sockaddr,client_sockaddr;
int sin_size,recvbytes;
int sockfd,client_fd;
char buf[MAXDATASIZE];
/*建立socket连接*/
if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1){
perror("socket");
exit(1);
}
printf("socket success! sockfd = %d\n", sockfd);
/*设置sockaddr_in结构体相关参数*/
server_sockaddr.sin_family = AF_INET;
server_sockaddr.sin_port = htons(SERVPORT);
server_sockaddr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_sockaddr.sin_zero),8);
/*绑定函数bind*/
if(bind(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(struct sockaddr)) == -1)
{
perror("bind");
exit(1);
}
printf("bind success!\n");
/*调用listen函数*/
if(listen(sockfd,BACKLOG) == -1)
{
perror("listen");
exit(1);
}
printf("listening...\n");
/*调用accept函数*/
if((client_fd = accept(sockfd,(struct sockaddr *)&client_sockaddr,&sin_size)) == -1)
{
perror("accept");
exit(1);
}
/*调用recv函数接收客户端的请求*/
if((recvbytes = recv(client_fd,buf,MAXDATASIZE,0)) == -1)
{
perror("recv");
exit(1);
}
printf("received a connection : %s\n",buf);
close(sockfd);
}
/*client.c*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define SERVPORT 3333
#define MAXDATASIZE 100
int main(int argc,char **argv)
{
int sockfd,sendbytes;
char buf[MAXDATASIZE];
struct hostent *host;
struct sockaddr_in serv_addr;
if(argc < 2)
{
fprintf(stderr,"Please enter the sercer's hostname!\n");
exit(1);
}
/*地址解析函数*/
if((host = (struct hostent *)gethostname(argv[1]))==NULL){
perror("gethostname");
exit(1);
}
/*创建socket*/
if((sockfd = socket(AF_INET, SOCK_STREAM,0)) == -1)
{
perror("socket");
exit(1);
}
/*设置sockaddr_in结构体相关参数*/
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERVPORT);
serv_addr.sin_addr=*((struct in_addr *)host->h_addr);
bzero(&(serv_addr.sin_zero),8);
/*调用connect函数主动发起对服务端的连接*/
if(connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(struct sockaddr)) == -1)
{
perror("connect");
exit(1);
}
/*发送消息给服务器*/
if((sendbytes = send(sockfd,"hello",5,0)) == -1){
perror("send");
exit(1);
}
close(sockfd);
}
Linux应用程序设计之网络基础编程的更多相关文章
- linux驱动程序设计的硬件基础,王明学learn
linux驱动程序设计的硬件基础(一) 本章讲总结学习linux设备程序设计的硬件基础. 一.处理器 1.1通用处理器 通用处理器(GPP)并不针对特定的应用领域进行体系结构和指令集的优化,它们具有一 ...
- [Linux]经典面试题 - 网络基础 - TCP三次握手
[Linux]经典面试题 - 网络基础 - TCP三次握手 目录 [Linux]经典面试题 - 网络基础 - TCP三次握手 一.TCP报文格式 1.1 TCP报头 1.2 报文图例 二.TCP三次握 ...
- 【苏勇老师Linux 入门笔记】网络基础
IP 地址 IP 编制时一个双层编制方案,一个 IP 地址标示一个主机 (或一个网卡接口). 一个 IP 地址分为两个部分:网络部分(所属区域)和主机部分(标示区域中的哪个主机).IPv4 共32位, ...
- C#网络程序设计(2)Socket基础编程
本节介绍如何使用基础Socket实现TCP通信. (1)Socket详细介绍: Socket的英文原义是"孔"或"插座".通常称作"套 ...
- 【网络基础编程】第三节 C/S
学习地址: C语言中文网 - 实现迭代服务端和客户端 GNU - Closing a Socket 前面介绍的程序,不管Service 端还是 Client端,都有一个问题,就是处理完一个 accep ...
- 网络基础编程_5.4聊天室-IOCP服务器
聊天室-IOCP服务器 main 创建完成端口内核对象(CreateIoCompletionPort) 获取核心数并创建线程(GetSystemInfo + CreateThread) 创建套接字并绑 ...
- linux需要了解的网络基础知识
第1章 网络命令 1.1 用户模式下的命令 1.1.1 enable切换到特权模式 Router>enable Router# 特权模式 Router# Router# 1.2 特权模式下的命令 ...
- 7)Linux程序设计入门--网络编程
)Linux程序设计入门--网络编程 Linux系统的一个主要特点是他的网络功能非常强大.随着网络的日益普及,基于网络的 应用也将越来越多. 在这个网络时代,掌握了Linux的网络编程技术,将令每一个 ...
- linux服务器开发三(网络编程)
网络基础 协议的概念 什么是协议 从应用的角度出发,协议可理解为"规则",是数据传输和数据的解释的规则. 假设,A.B双方欲传输文件.规定: 第一次,传输文件名,接收方接收到文件名 ...
随机推荐
- reduce()用法
reduce()方法接受一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终为一个值 参数 callback 执行数组中的每个值的函数,包含四个参数 previousValue 上一次调用回调 ...
- js给节点添加或删除类名
为 <div> 元素添加 class: document.getElementById(“myDIV”).classList.add(“mystyle”); 为 <div> 元 ...
- Teamproject Week7 --Scrum Meeting #1 2014.10.28
这是团队的第一次会议,具体议题如下: 1)我们明确了团队成员的职责所需: PM职责:根据项目范围.质量.时间与成本的综合因素的考虑,进行项目的总体规划与阶段计划. 控制项目组各成员的工作进度,即时了 ...
- OO前三次作业简单总结
随着几周的进行,OO课堂已经经历过三次课下作业.在这三次作业中,我被扣了一些分数,也发现了自己几次作业中一些存在的共同的问题. 首先以第三次作业为例分析,我程序的类图如下 一共九个类,其中Als_sc ...
- c# 程序重启设定
问题情境: 程序随着时间运行,越来越大.暂时想到的两种方法,一是反攻代码,查看占内存大的函数,是不是没有回收.再就是暴力设定程序定时重启. 解决原理: 定时重启:暂设定timer,时间匹配执行rest ...
- 优化Hibernate所鼓励的7大措施:
优化Hibernate所鼓励的7大措施: 1.尽量使用many-to-one,避免使用单项one-to-many 2.灵活使用单向one-to-many 3.不用一对一,使用多对一代替一对一 4.配置 ...
- Leetcode题库——24.两两交换链表中的节点
@author: ZZQ @software: PyCharm @file: swapPairs.py @time: 2018/10/20 19:49 说明:给定一个链表,两两交换其中相邻的节点,并返 ...
- 【CSAPP笔记】14. 异常控制流和进程
从给处理器加电,到断电为止,处理器做的工作其实就是不断地读取并执行一条条指令.这些指令的序列就叫做 CPU 的控制流(control flow).最简单的控制流是"平滑的",也就是 ...
- JS计算两个日期之间的天数,时间差计算
1.日期之间的天数计算 //计算天数差的函数,通用 function DateDiff(sDate1, sDate2) { //sDate1和sDate2是2017-9-25格式 var aDate, ...
- 关于SVM数学细节逻辑的个人理解(二):从基本形式转化为对偶问题
第二部分:转化为对偶问题进一步简化 这一部分涉及的数学原理特别多.如果有逻辑错误希望可以指出来. 上一部分得到了最大间隔分类器的基本形式: 其中i=1,2,3...m 直接求的话一看就很复杂,我们 ...