您的位置:首页 > 理论基础 > 计算机网络

Linux网络编程基础API

2017-03-17 20:06 471 查看
一、套接字的地址结构

1)IPv4套接字:

#include<netinet/in.h>
struct sockaddr_in
{
sa_family_t sin_family;     //地址族,AF_INET
u_int16_t sin_port;         //端口号,用网络字节表示
Struct in_addr sin_addr;    //IPv4地址结构,如下
};
struct in_addr
{
u_int32_t s_addr;           //IPv4地址,用网络字节序表示
};


2)IPv6:

struct sockaddr_in6
{
sa_family_t sin6_family;     //地址族,AF_INET6
u_int16 sin6_port;           //端口号,用网络字节表示
u_int32_t sin6_flowinfo;     //信息流,应设置为0
struct in6_addr sin6_addr;   //IPv6地质结构体,如下
u_int32_t sin6_scope_id;     //scope ID,现处实验阶段
};
struct in6_addr
{
unsigned cahr sa_addr[16];   //IPv6地址,用网络字节序表示
};


二、IP地址转换函数

由于人们喜欢用可读性好的字符串来表示IP地址,用点分十进制字符串表示IPv4,用十六进制字符串表示IPv6地址。但在网络中应把它们转化为二进制使用。而记录日志相反。以下三个函数可用于相互之间的转换:

#include<arpa/inet.h>
in_addr_t inet_addr(const char* strptr); //IPv4地址字符串->二进制
int inet_aton(const char* cp, struct in_addr* inp); //同上,结果存于inp指向的地址结构中
cahr* inet_ntoa(struct in_addr in); //网络字节->点分十进制(内部用静态变量存储转化结果,因此具有不可重入性)


下面两个更新的函数对IPv4和IPv6都可使用:

#include<arpa/inet.h>
int inet_pton(int af, const char* src, void* dst);
const char* inet_ntop(int af, const void* src, char* dst, socklen_t cnt);


上面的af指定地址族,dst指定结果存储的内存,cnt指定目标存储单元的大小。

下面两个宏定义了cnt的大小:

#include<netinet/in.h>
#define INET_ADDRESTRLEN 16
#define INET6_ADDRESTRLEN 46


三、创建socket

UNIX/Linux中:所有东西都是文件。socket也不例外,它就是可读、可写、可控制、可关闭的文件描述符。下面socket系统调用创建一个socket:

#include<sys/types.h>
#include<sys/socket.h>
int socket(int domain, int type, int protocol);
//             协议族  服务类型(流或数) 几乎默认为0


成功时创建一个文件描述符,失败返回-1,设置为errno。

四、命名socket:讲一个socket与socket地址绑定成为给socket命名。

#include<sys/types.h>
#include<sys/socket.h>
int bind(int sockfd, const struct sockaddr* my_addr, socklen_t addrlen);


bind成功时返回0,失败时返回-1,并设置errno。其中两个常见的errno为:

*EACCES,被绑定的地址受保护,仅超级用户能够访问。如普通用户将socket绑定到知名服务端口(0~1023)时,返回EACCES。

*EADDRINUSE,被绑定的地址正在使用中。比如把socket绑定到一个处于TIME_WAIT状态的socket。

五、监听socket

调用一个监听队列存放待处理的客户连接:

#include<sys/socket.h>
int listen(int sockfd, int backlog);
//                       监听队列的最大长度(典型参数为5)


六、接受连接

#include<sys/types.h>
#include<sys/socket.h>
int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen);
//                         获取被接受连接的远端socket地址    接收地址长度参数


accept只是从监听队列中取出连接,而不论连接处于何种状态,更不关心网络的变化。


七、发起连接

#include<sys/types.h>
#include<sys/socket.h>
int connect(int sockfd, const struct sockaddr* serv_addr, socklen_t addrlen);


八、关闭连接

关闭一个连接实际上就是关闭该连接对应的socket。

#include<unistd.h>
int close(int fd);  //fd->待关闭的socket


close系统调用并不非是立即关闭一个连接,而是将fd的引用计数减1,只有当fd的引用计数为0时,才真正关闭连接。

当无论如何都要立即终止连接,可以使用shutdown调用:


#include<sys/socket.h>
#int shutdown(int sockfd, int howto);


九、数据读写

对文件的读写操作read和write同样适用于socket。但socket的读写增加了对数据控制。用于TCP流数据读写的系统调用是:

ssize_t为:sign size_t类型的,可以被执行读写操作的数据块的大小。

(1)发送带外数据


#include<sys/types.h>
#include<sys/socket.h>
//                            位置         大小       默认0
ssize_t recv(int sockfd, void* buf, size_t len, int flags);
ssize_t send(int sockfd, const void* buf, size_t len, int flags);


几个重要的flags参数的可选值:

MSG_OOB:发送或接收紧急数据(提供带外数据的发送和接收)。

下面两个代码一个为发送带外数据,一个为接收带外数据。

#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<assert.h>
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>

int main(int argc, char* argv[])
{
int t = 1;
if(argc<=2)
{
printf("usage: %s ip_address port_number\n", basename(argv[0]));
return 1;
}
const char<
c758
/span>* ip = argv[1];
int port = atoi(argv[2]);

struct sockaddr_in server_address;
bzero(&server_address, sizeof(server_address));
server_address.sin_family = AF_INET;

inet_pton(AF_INET, ip, &server_address.sin_addr);
server_address.sin_port = htons(port);

int sockfd = socket(PF_INET, SOCK_STREAM,0);
assert(sockfd >=0);
if(connect(sockfd,(struct sockaddr*)&server_address,sizeof(server_address))<0)
{
printf("connection failed\n");
}
else
{
const char* oob_data = "wer";
const char* normal_data = "987";
send(sockfd, normal_data,strlen(normal_data), 0);
send(sockfd, oob_data,strlen(oob_data),MSG_OOB);
send(sockfd, normal_data,strlen(normal_data), 0);
scanf("%d\n", t);
}

close(sockfd);
return 0;

}


(2)接收带外数据


#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<assert.h>
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<errno.h>

#define BUF_SIZE 1024

int main(int argc, char* argv[])
{
if(argc<=2)
{
printf("usage: %s ip_address port_number\n", basename(argv[0]));
return 1;
}
const char* ip = argv[1];
int port = atoi(argv[2]);

struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
inet_pton(AF_INET, ip, &address.sin_addr);
address.sin_port = htons(port);

int sock = socket(PF_INET,SOCK_STREAM,0);
assert(sock>=0);

int ret = bind(sock,(struct sockaddr*)&address, sizeof(address));
assert(ret !=-1);

ret = listen(sock,5);
assert(ret !=-1);

struct sockaddr_in client;
socklen_t client_addrlength = sizeof(client);
int connfd = accept(sock, (struct sockaddr*)&client,&client_addrlength);
if(connfd<0)
{
printf("errno is: %d\n",errno);
}

else
{
char buffer[BUF_SIZE];

memset(buffer,'\0',BUF_SIZE);
ret = recv(connfd, buffer, BUF_SIZE-1, 0);
printf("got %d bytes of normal data '%s'\n", ret, buffer);

memset(buffer, '\0',BUF_SIZE);
ret = recv(connfd,buffer,BUF_SIZE-1,MSG_OOB);
printf("got %d bytes of oob data '%s'\n", ret, buffer);

memset(buffer, '\0',BUF_SIZE);
ret = recv(connfd, buffer, BUF_SIZE-1, 0);
printf("got %d bytes of normal data '%s'\n", ret, buffer);

close(connfd);

}

close(sock);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  网络编程