系统函数与库函数的区别:
系统函数可以说是原材料,库函数是对原函数的封装。
==================================================================
网络编程(UDP)
==================================================================
1.创建套接字:
函数原型:
int socket(int domain , int tpye , int potocol);
头文件:
#include <sys/types.h>
#include <sys/socket.h>
参数分析:
- domain ----> 定使用何种的地址类型, 完整的定义在/usr/include/bits/socket.h内, 底下是常见的协议:
PF_UNIX/PF_LOCAL/AF_UNIX/AF_LOCAL UNIX 进程通信协议
PF_INET/AF_INET Ipv4 网络协议
PF_INET6/AF_INET6 Ipv6 网络协议
PF_IPX/AF_IPX IPX-Novell 协议
PF_NETLINK/AF_NETLINK 核心用户接口装置
PF_X25/AF_X25 ITU-T X. 25/ISO-8208 协议
PF_AX25/AF_AX25 业余无线 AX. 25 协议
PF_ATMPVC/AF_ATMPVC 存取原始 ATM PVCs
PF_APPLETALK/AF_APPLETALK appletalk (DDP)协议
PF_PACKET/AF_PACKET 初级封包接口
- type --> 有下列几种数值:
SOCK_STREAM //提供双向连续且可信赖的数据流, 即 TCP. 支持 OOB 机制, 在所有数据传送前必须使用 connect()来建立连线状态.
SOCK_DGRAM 使用不连续不可信赖的数据包连接 说的就是UDP
SOCK_SEQPACKET 提供连续可信赖的数据包连接
SOCK_RAW 提供原始网络协议存取
SOCK_RDM 提供可信赖的数据包连接
SOCK_PACKET 提供和网络驱动程序直接通信
- protocol --> 用来指定 socket 所使用的传输协议编号, 通常此参考不用管它, 设为 0 即可.
反回值:
- 成功则返回 socket 处理代码(待链接的套接字)
失败返回-1.
==================================================================
2. 配置地址信息:
struct sockaddr_in
{
u_short sin_family; // 地址族
u_short sin_port; // 端口
struct in_addr sin_addr; // IPV4 地址
char sin_zero[8];
};
struct in_addr
{
in_addr_t s_addr; // 无符号 32 位网络地址
};
配置端口号
htons ( 将 16 位主机字符顺序转换成网络字符顺序 )
头文件:
#include <netinet/in.h>
定义函数:
unsigned short int htons(unsigned short int hostshort);
参数分析:
- hostshort ----> 需要转换的16位主机序整数
返回值:
- 返回对应的网络字符顺序
配置IPV4地址:
(1) inet_addr ( 将网络地址转成二进制的数字 )
头文件:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
定义函数:
unsigned long int inet_addr(const char *cp);
参数分析:
- cp ----> 网络地址字符串转换成网络所使用的二进制数字(需要转换的点分十进制网路地址)
返回值:
- 成功则返回对应的网络二进制的数字
失败返回-1.
(2) inet_ntoa ( 将网络二进制的数字转换成网络地址 )
头文件:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
定义函数:
char * inet_ntoa(struct in_addr in);
参数分析:
- in ----> 需要转换的二进制网路地址
返回值:
- 成功则返回字符串指针
失败则返回 NULL.
================================================================
3.绑定地址信息(服务器端):
bind ( 对 socket 定位 )
头文件:
#include <sys/types.h>
#include <sys/socket.h>
定义函数:
int bind(int sockfd, struct sockaddr * my_addr, int addrlen);
参数分析:
sockfd --> socket 处理代码 (socket的返回值待链接的套接字)
my_addr --> 包含本地地址(IP+PORT)的通用地址结构体的指针(sockaddr_in结构体)
addrlen --> 结构体长度
返回值:
- 成功:0
失败:-1
================================================================
4.等待来信(服务器端):
recvfrom ( 经 socket 接收数据 )
头文件:
#include <sys/types.h>
#include <sys/socket.h>
定义函数:
int recvfrom(int s, void *buf, int len, unsigned int flags, struct sockaddr *from,int *fromlen);
参数分析:
s --> 接收的socket套接字
buf --> 接收到的信息存放到哪里
len --> 接收信息的长度
- flags --> flags 一般设 0. 其他数值定义如下:
MSG_OOB 接收以 out-of-band 送出的数据.
MSG_PEEK 返回来的数据并不会在系统内删除, 如果再调用 recv()会返回相同的数据内容.
MSG_WAITALL 强迫接收到 len 大小的数据后才能返回, 除非有错误或信号产生.
MSG_NOSIGNAL 此操作不愿被 SIGPIPE 信号中断返回值成功则返回接收到的字符数, 失败返回-1,
from --> 信息来源哪里
fromlen --> 地址结构体的长度
返回值:
- 成功则返回接收到的字符数
失败则返回-1, 错误原因存于 errno 中.
=====================================================================
5.发送信息(客户端):
sendto ( 经 socket 传送数据 )
头文件:
#include <sys/types.h>
#include <sys/socket.h>
定义函数:
int sendto(int s, const void * msg, int len, unsigned int flags, const struct sockaddr * to, int tolen);
参数分析:
s --> 发送信息到那个socket
msg --> 待发送的信息
len --> 需要发送信息的长度
flags --> flags 一般设 0, 其他数值定义如下:
MSG_OOB 传送的数据以 out-of-band 送出.
MSG_DONTROUTE 取消路由表查询
MSG_DONTWAIT 设置为不可阻断运作
MSG_NOSIGNAL 此动作不愿被 SIGPIPE 信号中断.
to --> 发送信息到哪个地址
tolen --> 地址长度
返回值:
- 成功则返回实际传送出去的字符数
失败返回-1, 错误原因存于 errno 中.
====================================================================
6.数据缓存中涉及的问题:
(1) bzero ( 将一段内存内容全清为零 )
头文件:
#include <string.h>
定义函数:
void bzero(void *s, int n);
函数说明:
- bzero()会将参数 s 所指的内存区域前 n 个字节, 全部设为零值. 相当于调用 memset((void*)s, 0,size_tn);
(2) fgets ( 由文件中读取一字符串 )
头文件:
include<stdio.h>
定义函数:
char * fgets(char * s, int size, FILE * stream);
函数说明:
- fgets()用来从参数 stream 所指的文件内读入字符并存到参数 s 所指的内存空间, 直到出现换行字符、读到文件尾或是已读了 size-1 个字符为止, 最后会加上 NULL 作为字符串结束.
返回值:
- gets()若成功则返回 s 指针, 返回 NULL 则表示有错误发生.
================================================================
服务器UDP代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#define MSG_SIZE 1024
int main(int argc, char const *argv[])
{
//创建一个套接字:
int fd_socket = socket(AF_INET , SOCK_DGRAM , 0);
//配置地址信息:
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(6520); //主机字节序转换为网络字节序
addr.sin_addr.s_addr = inet_addr("192.168.162.129");
//绑定地址信息:
int addr_size = sizeof(addr);
int ret = bind(fd_socket, (struct sockaddr *) &addr, addr_size);
if(ret)
{
perror("bind error\n");
}
else
{
printf("bind succeed\n");
}
//等待来信:
struct sockaddr_in from_addr;
char *buf = malloc(MSG_SIZE);
while(1)
{
bzero(buf,MSG_SIZE);
recvfrom(fd_socket, buf, MSG_SIZE, 0,
(struct sockaddr *) &from_addr,
&addr_size);
printf("%s \tIP:%s\t Port:%d\n\n", buf,
inet_ntoa(from_addr.sin_addr),
ntohs(from_addr.sin_port));
}
return 0 ;
}
客户端UDP代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#define MSG_SIZE 1024
int main(int argc, char const *argv[])
{
//创建一个套接字:
int fd_socket = socket(AF_INET , SOCK_DGRAM , 0);
//配置地址信息:
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(6520); //主机字节序转换为网络字节序
addr.sin_addr.s_addr = inet_addr("192.168.162.129");
//发送信息:
struct sockaddr_in from_addr;
char *buf = malloc(MSG_SIZE);
while(1)
{
bzero(buf,MSG_SIZE);
fgets(buf, MSG_SIZE, stdin);
int ret = sendto(fd_socket, buf, MSG_SIZE, 0,
(struct sockaddr *) &addr, sizeof(addr));
if(-1 == ret)
{
perror("send error\n");
}
else
{
printf("send succeed\n");
}
}
return 0 ;
}