linux 网络编程
linux网络编程中主要分为服务器和客户端两部分,而网络编程中又分为TCP和UDP两种。
TCP(传输控制协议)和UDP(用户数据报协议是网络体系结构TCP/IP模型中传输层一层中的两个不同的通信协议。
TCP:传输控制协议,一种面向连接的协议,给用户进程提供可靠的全双工的字节流,TCP套接口是字节流套接口(stream socket)的一种。
UDP:用户数据报协议。UDP是一种无连接协议。UDP套接口是数据报套接口(datagram socket)的一种。
============================================TCP=======================================
A、建立服务器的步骤(TCP):
(1)创建TCP套接字: socket(int domain, int type, int protocol);
(2)设置端口号和IP: struct sockaddr_in (本结构体包含端口号和IP等信息)
(3)绑定套接字与网络地址 : bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
(4)将待连接套接字设置为监听套接字,并设置最大同时接收连接请求个数:listen(int socket, int backlog);
(5)等待客户端连接的请求:accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
(6)进行通信:recv(int sockfd, void *buf, size_t len, int flags);或用read()也可以
(7)关闭套接字:int close(int fildes);
B、建立客户端(TCP):
(1)创建TCP套接字:socket(int domain, int type, int protocol);
(2)设置服务器的IP与端口号:struct sockaddr_in (本结构体包含端口号和IP等信息)
(3)发送连接请求:connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
(4)进行通信:send(int sockfd, const void *buf, size_t len, int flags);或用write()也可以
(5)关闭套接字:int close(int fildes);
==========================================UDP========================================
A、建立服务器的步骤(UDP):
(1)创建UDP套接字: socket(int domain, int type, int protocol);
(2)设置端口号和IP: struct sockaddr_in (本结构体包含端口号和IP等信息)
(3)绑定套接字与网络地址 : bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
(4)进行通信:recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
(5)关闭套接字:int close(int fildes);
B、建立客户端(UDP):
(1)创建UDP套接字: socket(int domain, int type, int protocol);
(2)设置端口号和IP: struct sockaddr_in (本结构体包含端口号和IP等信息)
(3)进行通信:sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
(4)关闭套接字:int close(int fildes);
一、创建套接字
1、头文件 #include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
2、接口声明 int socket(int domain, int type, int protocol);
参数:
a、domain:
AF_INET / PF_INET :网际协议
AF_UNIX / PF_UNIX :本地协议
b、type:
SOCK_STREAM :流式套接字(TCP)
SOCK_DGRAM :数据报套接字(UDP)
c、protocol:协议
一般写为0 :当protocol为0时,会自动选择type类型对应的默认协议。
3、返回值:
成功:等待连接的套接字
失败:-1
二、绑定套接字与网络地址
1、头文件 #include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
2、接口声明 int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
参数:
a、sockfd:等待连接套接字
b、addr:包含本地地址(IP+PORT)的通用地址结构体的指针
c、addrlen:地址结构体大小
3、返回值:
成功:0
失败:-1
三、将待连接套接字设置为监听套接字,并设置最大同时接收连接请求个数
1、头文件 #include <sys/types.h>
#include <sys/socket.h>
2、接口声明 int listen(int socket, int backlog);
参数:
a、sockfd:待连接套接字
b、最大同时连接请求个数
3、返回值:
成功:0,并将sockfd设置为监听套接字
失败:-1
四、等待对端连接请求
1、头文件 #include <sys/types.h>
#include <sys/socket.h>
2、接口声明 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数:
a、sockfd:经过listen()之后的监听套接字
b、addr:本来为(struct sockaddr_in)型的结构体,但是写进来的时候要强转成为(struct sockaddr *)型
c、addrlen:为(struct sockaddr_in)结构体的大小
3、返回值:
成功:返回一个非负整数的文件描述符
失败-1
五、连接对端监听套接字
1、头文件 #include <sys/types.h>
#include <sys/socket.h>
2、接口声明 int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
参数:
a、sockfd:待连接的套接字
b、addr:本来为(struct sockaddr_in)型的结构体,但是写进来的时候要强转成为(struct sockaddr *)型
c、addrlen:为(struct sockaddr_in)结构体的大小
3、返回值:
成功:0
失败:-1
六、断开本端连接套接字
1、头文件 #include <unistd.h>
2、接口声明 int close(int fd);
参数:
a、fd:文件描述符
3、返回值:
成功:0
失败:-1
七、断开本端连接套接字
1、头文件 #include <sys/types.h>
#include <sys/socket.h>
2、接口声明 int shutdown(int sockfd, int how);
参数:
a、sockfd:accept()成功之后的已连接套接字(文件描述符)
b、how:断开方式
SHUT_RD
Disables further receive operations. //关闭读端
SHUT_WR
Disables further send operations. //关闭写端
SHUT_RDWR
Disables further send and receive operations. //关闭读写端
3、返回值:
成功:0
失败:-1
八、将文本地址转化为二进制地址
1、头文件 #include <arpa/inet.h>
2、接口声明 int inet_pton(int af, const char *src, void *dst);
参数:
a、af:地址族:
AF_INET:ipv4地址
AF_INET6:ipv6地址
b、src:指向“点分式”ipv4或ipv6地址的指针:例如:192.168.1.105
c、dst:类型为(struct in_addr *)的指针
3、返回值:
成功:1
失败:0代表地址与地址族不匹配,-1代表地址不合法
九、将二进制地址转化为文本地址
1、头文件 #include <arpa/inet.h>
2、接口声明 const char *inet_ntop(int af, const void *src,
char *dst, socklen_t size);
参数:
a、af:地址族:
AF_INET:ipv4地址
AF_INET6:ipv6地址
b、src:指向“点分式”ipv4或ipv6地址的指针:例如:192.168.1.105
c、dst:地址缓冲区指针
d、size:地址缓冲区大小
3、返回值:
成功:returns a non-NULL pointer to dst.
失败:NULL
十、向TCP套接字发送数据
1、头文件IS #include <sys/types.h>
#include <sys/socket.h>
2、接口声明 ssize_t send(int sockfd, const void *buf, size_t len, int flags);
参数:
a、sockfd:已连接的套接字
b、buf:即将被发送的数据
c、len:数据长度
d、flags:发送标志(可以填0)
MSG_EOR:当对端已关闭时,不产生SIGPIPE信号
MSG_OOB :发送紧急(带外)数据,只针对TCP连接
3、返回值:
成功:已发送字节数
失败:-1
备注当flags为0时,send与write作用一样,所以TCP也可以用write发送数据
十一、从TCP套接字接收数据
1、头文件 #include <sys/types.h>
#include <sys/socket.h>
2、接口声明 ssize_t recv(int sockfd, void *buf, size_t len, int flags);
参数:
a、sockfd:已连接套接字
b、buf:存储数据缓冲区
c、len:缓冲区大小
d、flags:接收标志(可以填0)
3、返回值:
成功:已接收字节数
失败:-1
备注当flags为0时,recv与read作用一样,所以TCP也可以用read来接收数据
十二、向UDP套接字发送数据
1、头文件 #include <sys/types.h>
#include <sys/socket.h>
2、接口声明 ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
参数:
a、sockfd:UDP(套接字) (SOCK_DGRAM :数据报套接字)
b、buf:即将被发送的数据
c、len:数据长度
d、flags:发送标志:与send函数的flags一样
e、dest_addr:对端网络地址
f、addr_len:地址长度 (struct sockaddr_in 的大小)
3、返回值:
成功:已发送字节数
失败:-1
备注:
当dest_addr为NULL,aaddrlen为0时,sendto与send作用一致
十三、从UDP套接字接收数据
1、头文件 #include <sys/types.h>
#include <sys/socket.h>
2、接口声明 ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
参数:
a、sockfd:UDP(套接字) (SOCK_DGRAM :数据报套接字)
b、buf:存储数据缓冲区
c、len:缓冲区大小
d、flags:接收标志:与send函数的flags一样
e、dest_addr:对端网络地址
f、addr_len:地址长度 (struct sockaddr_in 的大小)
3、返回值:
成功:已接收字节数
失败:-1
十四、多路复用
1、头文件 #include <sys/select.h>
2、接口声明 int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
参数:
a、nfds:所有正在监测的套接字的最大值加1
b、readfds:读就绪文件描述符集合
c、writefds:写就绪文件描述符集合
d、execeptfds:异常就绪文件描述符集合
e、timeout:超时控制
3、返回值:
成功:就绪文件描述符总数(当超过返回时为0)
失败-1
超时设置:
The timeout
The time structures involved are defined in <sys/time.h> and look like
struct timeval {
long tv_sec; /* seconds */ 秒
long tv_usec; /* microseconds */ 微秒
};
and
struct timespec {
long tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */ 纳秒
};
文件描述符集合操作函数:
void FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);
下面是简单的例子,服务器负责接收数据,客户端负责发送数据。
================================下面为TCP的代码=====================
1、服务器:service.c
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <linux/in.h>
#include <stdlib.h>
#include <string.h> #define IP "192.168.1.104" //这是我的虚拟机上的IP,读者要改成自己的IP
#define PORT 50001 //端口号(可改)
#define LISTEN_MAX 8 //最大同时接收连接请求个数
#define LENGTH 100 //数组的大小 int main(int argc,char *argv[])
{
int sockfd;
char buf[LENGTH];
//1、创建TCP套接字(SOCK_STREAM为TCP),AF_INET为ipv4
sockfd = socket(AF_INET,SOCK_STREAM,);
if(sockfd == -)
{
perror("socket");
exit();
} //2、设置端口号和IP
struct sockaddr_in srvaddr,cliaddr;
socklen_t len = sizeof(cliaddr);
srvaddr.sin_family = AF_INET; //ipv4
srvaddr.sin_port = htons(PORT); //端口号
inet_pton(AF_INET,IP,&srvaddr.sin_addr); //将文本地址转化为二进制地址 //3、绑定套接字与网络地址
int ret = bind(sockfd,(struct sockaddr *)&srvaddr,len);
if(ret == -)
{
perror("bind");
exit();
} //4、将待连接套接字设置为监听套接字,并设置最大同时接收连接请求个数4、
int ret1 = listen(sockfd,LISTEN_MAX);
if(ret1 == -)
{
perror("listen");
exit();
} //5、等待客户端端连接的请求,这是阻塞的
int connfd = accept(sockfd,(struct sockaddr*)&cliaddr,&len);
if(connfd == -)
{
perror("accept");
exit();
} while()
{
memset(buf,,sizeof(buf));
recv(connfd,buf,sizeof(buf),); //读出客户端发送过来的数据,这里可以用read代替
printf("from client:%s",buf); if(strncmp(buf,"quit",) == )
{
break;
}
} close(connfd);
close(sockfd);
}
2、客户端:client.c
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <linux/in.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h> #define IP "192.168.1.104" //这是我的虚拟机上的IP,读者要改成自己的IP
#define PORT 50001 //端口号(要跟服务器上的一致)
#define LENGTH 100 //数组大小
int main(int argc,char *argv[])
{
char buf[LENGTH]; //1、创建TCP套接字(SOCK_STREAM为TCP),AF_INET为ipv4
int sockfd = socket(AF_INET,SOCK_STREAM,);
if(sockfd == -)
{
perror("socket");
exit();
} //2、设置服务器的IP与端口号
struct sockaddr_in srvaddr;
socklen_t len = sizeof(srvaddr);
srvaddr.sin_family = AF_INET; //ipv4
srvaddr.sin_port = htons(PORT); //端口号
inet_pton(AF_INET,IP,&srvaddr.sin_addr); //将文本地址转化为二进制地址 //3、发送连接请求,这是阻塞的
int ret = connect(sockfd,(struct sockaddr*)&srvaddr,len);
if(ret == -)
{
perror("connect");
exit();
} while()
{
memset(buf,,sizeof(buf));
fgets(buf,sizeof(buf),stdin);
send(sockfd,buf,strlen(buf),); //向服务器发送数据,这里可以用write代替 if(strncmp(buf,"quit",) == )
{
break;
}
} close(sockfd);
return ;
}
================================下面为UDP的代码=====================
1、服务器:service.c
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <linux/in.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h> #define IP "192.168.1.104" //这是我的虚拟机上的IP,读者要改成自己的IP
#define PORT 50002 //端口号
#define LENGTH 100 //数组大小 int main(int argc,char *argv[])
{
// 1、创建UDP套接字 ,AF_INET为iPv4,SOCK_DGRAM为UDP
int sockfd = socket(AF_INET,SOCK_DGRAM,) ;
if(sockfd == -)
{
perror("socket");
exit();
} //2、设置端口号和IP
struct sockaddr_in srvaddr,cliaddr;
socklen_t len = sizeof(cliaddr);
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = PORT;
inet_pton(AF_INET,IP,&srvaddr.sin_addr); //将文本地址转化为二进制地址 //3、绑定套接字与网络地址
int ret = bind(sockfd,(struct sockaddr*)&srvaddr,sizeof(srvaddr));
if(ret == -)
{
perror("bind");
exit();
} char buf[LENGTH];
while()
{
memset(buf,,sizeof(buf));
recvfrom(sockfd,buf,sizeof(buf),,(struct sockaddr*)&cliaddr,&len);
printf("from client:%s",buf);
if(strncmp(buf,"quit",) == )
{
break;
}
} close(sockfd);
return ; }
2、客户端:client.c
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <linux/in.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h> #define IP "192.168.1.104" //这是我的虚拟机上的IP,读者要改成自己的IP
#define PORT 50002 //端口号(要跟服务器上的一致)
#define LENGTH 100 //数组大小 int main(int argc,char *argv[])
{
//1、创建UDP套接字(SOCK_DGRAM为UDP),AF_INET为ipv4
int sockfd = socket(AF_INET,SOCK_DGRAM,);
if(sockfd == -)
{
perror("socket");
exit();
} //2、设置对方的IP与端口号
struct sockaddr_in srvaddr;
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = PORT;
inet_pton(AF_INET,IP,&srvaddr.sin_addr);//将文本地址转化为二进制地址 char buf[LENGTH];
while()
{
memset(buf,,sizeof(buf));
fgets(buf,sizeof(buf),stdin);
sendto(sockfd,buf,strlen(buf),,(struct sockaddr*)&srvaddr,sizeof(srvaddr));
if(strncmp(buf,"quit",) == )
{
break;
}
} close(sockfd);
}
linux 网络编程的更多相关文章
- 【深入浅出Linux网络编程】 "开篇 -- 知其然,知其所以然"
[深入浅出Linux网络编程]是一个连载博客,内容源于本人的工作经验,旨在给读者提供靠谱高效的学习途径,不必在零散的互联网资源中浪费精力,快速的掌握Linux网络编程. 连载包含4篇,会陆续编写发出, ...
- 【linux草鞋应用编程系列】_5_ Linux网络编程
一.网络通信简介 第一部分内容,暂时没法描述,内容实在太多,待后续专门的系列文章. 二.linux网络通信 在linux中继承了Unix下“一切皆文件”的思想, 在linux中要实现网 ...
- Linux 网络编程(IO模型)
针对linux 操作系统的5类IO模型,阻塞式.非阻塞式.多路复用.信号驱动和异步IO进行整理,参考<linux网络编程>及相关网络资料. 阻塞模式 在socket编程(如下图)中调用如下 ...
- linux网络编程 no route to host 解决方案
linux网络编程 no route to host 解决方案 [整合资料] (2013-05-13 21:38:12) 转载▼ 标签: net iptables it 分类: Linux 参考资料h ...
- linux网络编程-(socket套接字编程UDP传输)
今天我们来介绍一下在linux网络环境下使用socket套接字实现两个进程下文件的上传,下载,和退出操作! 在socket套接字编程中,我们当然可以基于TCP的传输协议来进行传输,但是在文件的传输中, ...
- Linux网络编程&内核学习
c语言: 基础篇 1.<写给大家看的C语言书(第2版)> 原书名: Absolute Beginner's Guide to C (2nd Edition) 原出版社: Sams 作者: ...
- linux网络编程_1
本文属于转载,稍有改动,以利于学习. (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个 ...
- Linux网络编程入门 (转载)
(一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...
- Linux网络编程必看书籍推荐
首先要说讲述计算机网络和TCP/IP的书很多. 先要学习网络知识才谈得上编程 讲述计算机网络的最经典的当属Andrew S.Tanenbaum的<计算机网络>第五版,这本书难易适中. &l ...
- [转] - Linux网络编程 -- 网络知识介绍
(一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...
随机推荐
- 每天来点Java面试题(一)
(1)java 中的 static 字段的 使用: 什么是 static ? 它是 java 的修饰符,定义静态变量和静态方法. 什么时候用? 通常用在工具类里面,修饰静态方法,然后供其它类的方法使 ...
- Collections 的 synchronized XXX方法
摘要 static <T> Collection<T> synchronizedCollection(Collection<T> c) 返回指定 collectio ...
- (转)每天一个linux命令(27):linux chmod命令
场景:在项目部署过程中经常需要给不同目录授权! 1 简介 chmod命令用于改变linux系统文件或目录的访问权限.用它控制文件或目录的访问权限.该命令有两种用法.一种是包含字母和操作符表达式的文字设 ...
- vue组件的那些事($children,$refs,$parent)的使用
如果项目很大,组件很多,怎么样才能准确的.快速的寻找到我们想要的组件了?? 1)$refs 首先你的给子组件做标记.demo :<firstchild ref="one"&g ...
- zabbix 配置发送邮件报警
标签:监控/SQLServer/Windows 概述 本篇文章主要介绍如何配置zabbix借助外部邮件进行发送邮件报警,zabbix通过配置文件调用mailx来进行邮件的发送.在Centos6以上的版 ...
- MySql 求一段时间范围内的每一天,每一小时,每一分钟
平常经常会求一段时间内的每一天统计数据,或者每一时点的统计数据.但是mysql本身是没有直接获取时点列表的函数或表.下面是自己用到的一些方法,利用临时变量和一个已存在的比较多数据(这个需要根据实际情况 ...
- yii2 队列 shmilyzxt/yii2-queue 简介
在yii2论坛中看到一个关于队列的帖子,感觉不错.http://www.yiichina.com/extension/1084 (注:SendMail 错写为 SendMial,粘贴时要注意了.) 在 ...
- webpack2 前篇
webpack2 前篇 #webpack 前两天用了一天半时间琢磨了下webpack2,想起去年这时候,面对webpack1那样恶心的文档,前前后后搞了好几次才摸索清楚,那真是吐了. 划重点 其实we ...
- 时间戳,取值问题 and 倒计时的前端处理
JavaScript 获取当前时间戳: 第一种方法: var timestamp = Date.parse(new Date()); 获取的时间戳是把毫秒改成000显示, 结果:12809773300 ...
- 贪心:字典树openjudge1799-最短前缀
描述 一个字符串的前缀是从该字符串的第一个字符起始的一个子串.例如 "carbon"的字串是: "c", "ca", "car&q ...