【Unix网络编程】第一章

daytimetcpcli.c

#include "unp.h"
#include "my_err.h"

int
main(int argc, char **argv)
{
	int					sockfd, n;
	char				recvline[MAXLINE + 1];
	struct sockaddr_in	servaddr;

	if (argc != 2)
		err_quit("usage: a.out <IPaddress>");

	if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
		err_sys("socket error");

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port   = htons(13);	/* daytime server */
	if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
		err_quit("inet_pton error for %s", argv[1]);

	if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0) err_sys("connect error"); while ( (n = read(sockfd, recvline, MAXLINE)) > 0) {
		recvline[n] = 0;	/* null terminate */
		if (fputs(recvline, stdout) == EOF)
			err_sys("fputs error");
	}
	if (n < 0)
		err_sys("read error");

	exit(0);
}

 

创建TCP套接字

使用函数,参考链接:
[dm href=’http://baike.baidu.com/link?url=sGKti6WLouLRLE3481kH_uf5DUcmNCOnjWBIBe3I08OzUHKu3o35fioN9CeybOonnxdEgTTyu-jW7WhKpMUTUK’]百度百科参考[/dm]

int socket(int domain, int type, int protocol);

其中domain表示何种地址类型

type参数的作用是设置通信的协议类型

参数protocol用来指定socket所使用的传输协议编号。这一参数通常不具体设置,一般设置为0即可

网际套接字地址结构

在《unix网络编程书中》把服务器IP地址和端口号填入一个网络套接字地址结构

即:一个名为servaddr的sockaddr_in结构变量

/*IPv4地址结构*/
struct sockaddr_in
{
    uint8_t sin_len;
    sa_family_t sin_family;//地址族
    in_port_t sin_port;//端口号 16位 两个字节
    struct in_addr sin_addr;//地址 32位 四个字节
    char sin_zero[8];//保留字段,一般不使用,一般将其设置为0
};
struct in_addr
{
    unit32_t s_addr; //地址应该为网络字节序
};
sin_len:结构体大小,有一些平台下没有这个字段
sin_family:指定该地址家族(地址族),在IPv4套接字地址结构中,必须为AF_INET
//socket不仅能用与TCP/IP协议,还可以用于Unix域协议
AF_INET6 为IPv6协议

sin_addr:IPv4的地址,结构体,结构体中只有一个成员,成员为无符号的32位整数
sin_port:无符号的16位整数,最大值是65535

在上述地址结构中,只需要注意地址族,端口号,地址即可。

通用地址结构:

struct sockaddr
{
    unit8_t sin_len;
    sa_family_t sin_family;
    char sa_data[14];//14个字节
}
sin_len:整个sockaddr结构体的长度
sin_family:指定该地址家族
sa_data:由sin_family决定它的形式

有可能不在TCP/IP协议中,所以一般使用通用地址,

使用顺序是填充第一类地址,再将第一类地址强制转换为第二类地址

比如:

struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(5188);
//servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

//连接服务器
if(connect(sock, (struct sockaddr*)&servaddr, sizeof(servaddr))<0)
    ERR_EXIT("connect");

memset和bzero

在使用地址结构之前需要将地址结构清零,至于为什么需要清零我还不是很了解

如果各位读者有所了解,欢迎评论。

memset函数:

void *memset(void *s, int ch, size_t n);

memset的大致含义为将s的前n个字节填充为ch

如上述定义地址结构中使用的memset函数。

memset(&servaddr, 0, sizeof(servaddr));

bzero函数:

置字节字符串前n个字节为零且包括‘\0’

如《unix网络编程》中使用的:

bzero(&servaddr, sizeof(servaddr));

字节序

大端字节序:内存地址增长的方向->将高位的数据存放在低内存地址处

小端字节序:将高位的数据存放在高内存地址处

其中:网络字节序为大端字节序

相关函数:

/*与字节序相关的转换函数*/
unit32_t htonl(unit32_t hostlong); //由4个字节的整数,有主机字节序转换为网络字节序
unit16_t htons(unit16_t hostshort);//由2个字节的整数,有主机字节序转换为网络字节序
unit32_t ntohl(unit32_t netlong);
unit16_t ntohs(unit16_t netshort);

在上述函数中,h代表host, n代表network, s代表short, l代表long

地址转换函数:

/*地址转换函数*/
#include <netinet/in.h>
#include <arpa/inet.h>

int inet_aton(const char *cp, struct in_addr *inp);
//将点分十进制的ip地址转换成网络地址
int_addr_t inet_addr(const char *cp);
//将点分十进制的ip地址转换成32位的整数
char *inet_ntoa(struct in_addr in);
//将网络字节序的地址结构转换成点分十进制的ip地址

 

 

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部