不管是 Windows 还是 Linux,都使用 socket() 函数来创建套接字。socket() 在两个平台下的参数是相同的,不同的是返回值:
(1)Linux 中的一切都是文件,每个文件都有一个整数类型的文件描述符;socket 也是一个文件,也有文件描述符。使用 socket() 函数创建套接字以后,返回值就是一个 int 类型的文件描述符。
(2)Windows 会区分 socket 和普通文件,它把 socket 当做一个网络连接来对待,调用 socket() 以后,返回值是 SOCKET 类型,用来表示一个套接字。
在 Linux 下使用
int socket(int af, int type, int protocol);
参数:
int tcp_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //IPPROTO_TCP表示TCP协议
struct sockaddr和struct sockaddr_in这两个结构体用来处理网络通信的地址
1、sockaddr
sockaddr在头文件#include
struct sockaddr {
sa_family_t sin_family;//地址族
char sa_data[14]; //14字节,包含套接字中的目标地址和端口信息
};
2、sockaddr_in
sockaddr_in在头文件#include
sin_port和sin_addr都必须是网络字节序(NBO),一般可视化的数字都是主机字节序(HBO)。
3、总结
二者长度一样,都是16个字节,即占用的内存大小是一致的,因此可以互相转化。二者是并列结构,指向sockaddr_in结构的指针也可以指向sockaddr。
sockaddr常用于bind、connect、recvfrom、sendto等函数的参数,指明地址信息,是一种通用的套接字地址。
sockaddr_in 是internet环境下套接字的地址形式。所以在网络编程中我们会对sockaddr_in结构体进行操作,使用sockaddr_in来建立所需的信息,最后使用类型转化就可以了。一般先把sockaddr_in变量赋值后,强制类型转换后传入用sockaddr做参数的函数:sockaddr_in用于socket定义和赋值;sockaddr用于函数参数。
#include
#include
#include
#include
int main(int argc,char **argv)
{
int sockfd;
struct sockaddr_in mysock;
sockfd = socket(AF_INET,SOCK_STREAM,0); //获得fd
bzero(&mysock,sizeof(mysock)); //初始化结构体
mysock.sin_family = AF_INET; //设置地址家族
mysock.sin_port = htons(800); //设置端口
mysock.sin_addr.s_addr = inet_addr("192.168.1.0"); //设置地址
bind(sockfd,(struct sockaddr *)&mysock,sizeof(struct sockaddr); /* bind的时候进行转化 */
... ...
return 0;
}
描述:
inet_addr()作用是将一个IP字符串转化为一个网络字节序的整数值
返回值:
若无错误发生,inet_addr()返回一个无符号长整型数,其中以适当字节顺序存放Internet地址。如果传入的字符串不是一个合法的Internet地址,如“a.b.c.d”地址中任一项超过255,那么inet_addr()返回INADDR_NONE
函数原型:
struct hostent* gethostbyname(const char *name);
调用函数成功返回一个hostent结构体
struct hostent
{
char *h_name;
char ** h_aliases;
short h_addrtype;
short h_length;
char ** h_addr_list;
};
测试代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc,char *argv[])
{
int optret;
char *ipname = NULL;
char ip[50];
struct hostent *gethost = NULL;
int file_fd;
char buf[50];
char *ptrf;
char *ptrb;
int n;
char fptr[50];
const char *ptr = NULL;
struct in_addr inAddr;
while((optret = getopt(argc,argv,"i:")) != -1)
{
switch(optret)
{
case 'i':
ipname = optarg;
printf("option = i,the ipname is:%s\n",optarg);
break;
}
}
gethost = gethostbyname(ipname);
if (NULL == gethost)
{
perror("get ipaddr fail!");
return -1;
}
printf("get host successfully!\n");
memset(ip,0,sizeof(ip));
ptr = inet_ntop(gethost->h_addrtype,gethost->h_addr_list[0],ip,sizeof(ip));
printf("DNS ip is:%s\n",ptr);
system("ping studio.iot-yun.com -c 2 >> /home/deepin/APUE/malunkun/test/.domain.log");
file_fd=open("/home/deepin/APUE/malunkun/test/.domain.log",O_RDONLY,644);
if (file_fd < 0)
{
perror("open file fail!\n");
}
read(file_fd,buf,sizeof(buf));
close(file_fd);
ptrf = strstr(buf,"(");
ptrf += 1;
ptrb = strstr(buf,")");
n = strlen(ptrf)-strlen(ptrb);
strncpy(fptr,ptrf,n);
printf("ping ip is:%s\n",fptr);
return 0;
}
这两个函数仅用于套接字。
函数原型:
#include
#include
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
sockfd:必须指向一个打开的套接字描述符
level:指定系统中解释选项的代码或为通用套接字代码,或为某个特定于协议的代码(例如IPv4IPv6、TCP或SCTP)。
optval:指向某个变量(*optval)的指针,setsockopt从optval中取得选项设置的新值,getsockopt则把以获取的选项当前值存入optval。
optlen:指定*optval的大小
套接字选项的汇总可以查看unix网络编程(卷1)151页 图7-1和图7-2