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

网络编程常见函数解析

2012-06-07 08:16 323 查看
最近重学了网络编程,顺便修改了国嵌的网络编程视频一节的tcp服务器程序,颇有心得。

先介绍函数以供以后使用。

函数1、int socket(int domain, int type, int protocol);(以后的每个函数后面的英文都是摘自posix标准)

The socket() function shall create an unbound socket in a communications domain, and return a file descriptor that can be used in later function calls that operate on sockets.

其中第一个形参是协议族,如AF_INET(IP协议族),第二个形参是socket的类别,其中有三种:SOCK_STREAM(用于TCP)、SOCK_DGRAM(用于UDP)、SOCK_RAW(主要用于新网络协议的测试),返回值是socket描述符。

例子:int sockfd=socket(AF_INET,SOCK_STREAM,0);

函数2、int bind(int socket, const struct sockaddr *address,socklen_t address_len);

The bind() function shall assign a local socket address address to a socket identified by descriptor socket that has no local socket address assigned. Sockets created with the socket() function are initially unnamed; they are identified only by their address family.

第一个形参是你刚才创建的套接字描述符,(这个是用在服务器上的函数),第二个形参是结构体struct sockaddr,注意的是我们经常使用sockaddr_in结构体,所以在这里使用时必须强制类型转换。第三个形参是对结构体求大小,用sizeof。这里我说一个困惑:不知道为什么,如果在函数的开头定义部分,将一个指针指向sockaddr_in结构体即struct sockaddr_in *server_sock,会出现段错误的提示,执行不了,不知为什么??

例子:

int bind_ret=bind(sockfd,(struct sockaddr *)(&server_sock),sizeof(struct sockaddr_in));

函数3、int listen(int socket, int backlog);

The listen() function shall mark a connection-mode socket, specified by the socket argument, as accepting connections.

第一个形参一样,不讲。第二个是指定你的服务器能处理的最大连接数目。

例子: listen_ret=listen(sockfd,MAX_CONNUM);

函数4、int accept(int socket, struct sockaddr *restrict address,socklen_t *restrict address_len);

The accept() function shall extract the first connection on the queue of pending connections, create a new socket with the same socket type protocol and address family as the specified socket, and allocate a new file descriptor for that socket.

第一个形参是你服务器创建的套接字描述符(这个函数也是用在服务器上),第二个形参是你的客户端的sockaddr(sockaddr_in)结构体,第三个形参是该结构体的大小。

例子:

accept_sockfd=accept(sockfd,(struct sockaddr *)(&client_sock),&size))

函数5、int connect(int socket, const struct sockaddr *address,socklen_t address_len);

The connect() function shall attempt to make a connection on a socket.

第一个形参是你客户端创建的套接字描述符,第二个形参是服务器端的sockaddr结构体,之后第三个是该结构体长度。这个函数用在客户端上,注意了,在客户端上我们需要填写的服务器端的sockaddr结构体,这样与服务器端相匹配到时才能按照网咯地址找到服务器端。

至于读写我们可以用read、write或是recv、send函数,这里就不介绍了。

例子:

connect_ret=connect(sockfd,(struct sockaddr *)(&server_sock),sizeof(struct sockaddr_in);

函数6、htons与htonl、ntons、ntonl。原型分别是:

#include <arpa/inet.h>

uint32_t htonl(uint32_t hostlong);

uint16_t htons(uint16_t hostshort);

uint32_t ntohl(uint32_t netlong);

uint16_t ntohs(uint16_t netshort);

these functions shall convert 16-bit and 32-bit quantities between network byte order and host byte order.On some implementations, these functions are defined as macros.The uint32_t and uint16_t types are defined in <inttypes.h>.

形参是你想转换的值。

函数7、地址转换函数:

#include <arpa/inet.h>

in_addr_t inet_addr(const char *cp);

char *inet_ntoa(struct in_addr in);

The inet_addr() function shall convert the string pointed to by cp, in the standard IPv4 dotted decimal notation, to an integer value suitable for use as an Internet address.

The inet_ntoa() function shall convert the Internet host address specified by in to a string in the Internet standard dot notation.

例子:

函数8、获取主机信息的结构体函数:

struct hostent *gethostbyname(const char *name);

struct hostent *gethostbyaddr(const void *addr, socklen_t len,

int type);

These functions shall retrieve information about hosts. This information is considered to be stored in a database that can be accessed sequentially or randomly. Implementation of this database is unspecified.

例子:structhosten *host; host=gethostbyname(argv[1]);

以上就是网络编程需要常用的函数,这是应用层的。以下是我的改编函数,还有很多不足,原理编写一个简单的并发服务器,可以同时处理多个客户端的要求,并且在客户端中,如果你什么都不输入而直接按ENTER键的话会提示你是否真要退出,若否则按ENTER键确认默认选择,否则按y退出,在服务器端也会判断客户端是否真要退出,判断不成立的话继续接受客户端的信息,可能写的不是很好,但愿看得懂!:

服务器函数:

#include <stdlib.h>

#include <stdio.h>

#include <error.h>

#include <strings.h>

#include <netdb.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <sys/socket.h>

#define portnumber 12345

#define MAX_BUF 1024

#define MAX_CONNUM 10

int main(int argc,char *argv[])

{

int sockfd;

struct sockaddr_in server_sock;

struct sockaddr_in client_sock;

char buff[MAX_BUF];

int nbytes;

int listen_ret;

int client_num=0;

if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)

{

fprintf(stderr,"create a server socket fail\n");

exit(1);

}

bzero(&server_sock,sizeof(&server_sock));

server_sock.sin_family=AF_INET;

server_sock.sin_port=htons(portnumber);

server_sock.sin_addr.s_addr=htonl(INADDR_ANY);

//server_sock.sin_addr.s_addr=inet_addr("192.168.0.117");

int bind_ret=bind(sockfd,(struct sockaddr *)(&server_sock),sizeof(struct sockaddr_in));

if (bind_ret==-1)

{

perror("bind failed\n");

exit(1);

}

if( listen_ret=listen(sockfd,MAX_CONNUM)<0)

{

perror("listen failed\n");

exit(1);

}

while(1)

{

int accept_sockfd;

int size=sizeof(struct sockaddr_in);

if((accept_sockfd=accept(sockfd,(struct sockaddr *)(&client_sock),&size))<0)

{

fprintf(stderr,"server accept error!!\n");

exit(1);

}

client_num++;

printf("server get connection from %s,the num of client is %d\n",inet_ntoa(client_sock.sin_addr),client_num);

if(fork()==0)

{

do

{

nbytes=read(accept_sockfd,buff,MAX_BUF);

buff[nbytes-1]='\0';

if(buff[0]=='\0')

{

printf("this time we recieve nothing from the client!\nwe wait the client quit or not\n");

nbytes=read(accept_sockfd,buff,MAX_BUF);

buff[nbytes-1]='\0';

if(buff[0]!='\0')

printf("client %d still not quit,we can continue recieve msg\n",client_num);

}

else

printf("we recieve the string of %s from the client %d\n",buff,client_num);

}while(buff[0]!='\0');

close(accept_sockfd);

printf("so the num of client %d has quit!\n",client_num);

exit(0);

}

}

close(sockfd);

exit(0);

}

客户端:

#include <stdlib.h>

#include <stdio.h>

#include <error.h>

#include <string.h>

#include <netdb.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <sys/socket.h>

#define portnumber 12345

int main(int argc,char *argv[])

{

int sockfd;

struct sockaddr_in server_sock;

struct hostent *host;

int nbytes;

char buf[1024];

char str;

if(argc!=2)

{

fprintf(stderr,"Usage:%s hostneme \a\n",argv[0]);

exit(1);

}

if((host=gethostbyname(argv[1]))==NULL)

{

fprintf(stderr,"get hostname error\n");

exit(1);

}

sockfd=socket(AF_INET,SOCK_STREAM,0);

if(sockfd==-1)

{

fprintf(stderr,"create a client socket fail\n");

exit(1);

}

bzero(&server_sock,sizeof(&server_sock));

server_sock.sin_family=AF_INET;

server_sock.sin_port=htons(portnumber);

server_sock.sin_addr=*((struct in_addr*)host->h_addr);

//server_sock->sin_addr.S_addr=inet_aton("192.168.1.11",ip_addr);

int connect_ret;

char *reply="not exit";

if(connect_ret=connect(sockfd,(struct sockaddr *)(&server_sock),sizeof(struct sockaddr_in))<0)

{

fprintf(stderr,"client get connection failed\n");

exit(1);

}

while(1)

{

printf("please input something\n");

fgets(buf,1024,stdin);

nbytes=write(sockfd,buf,strlen(buf));

if (nbytes<0)

{

printf("send failed\n");

exit(1);

}

buf[strlen(buf)-1]='\0';

if(strlen(buf)==0)

{

printf("You input nothing and press ENTER key,so we consider you want to quit the client!\n");

printf("Are you sure to quit the client?the default choice is not,if you do not want to exit,you can press ENTER key!\n");

str=getchar();

if(str=='y')

break;

else

if(str=='\n')

{

printf("you still not want to quit the client!\n");

write(sockfd,reply,8);

}

}

else

printf("we send %d octets from the client,string is %s\n",strlen(buf),buf);

}

printf("the client has quit!you need not input anything!\n");

close(sockfd);

exit(0);

}

接下来介绍几个上周用过的函数:

函数9、绝对值函数:int abs(int a);long int labs(long int b);

函数10、求商与余数函数:div_t div(int numerator,int denominator);ldiv_t div(long int numerator,long int denominator);

div_t是一个结构体,包含了商与余数两个字段。第一个形参是分子,第二个是分母。

函数11、随机数函数:int rand(void);void srand(unsigend int seed);

函数12、字符串转换函数:int atoi(char const *string);------将合法的字符转换为指定的值。

long int atol(char const *string);

以上两个函数均是以10为基数,待会在介绍怎么转换的。

long int strtol(char const *string ,char **unused,int base),

unsigned long int strtoul(char const *string ,char ** unused ,int base)

这两个函数功能比前面两个强一点,可以指出转换到哪结束,并将指针指向那里,而且基数可以自己指定。这里附上一个例子程序。

怎么转换的呢?举个例子:用第一个函数,输入“13ab”,输出是13,ab对于基数10来讲是非法数值。而采用第三个函数时,基数我们假定为15,则输出的是4211,这样算的((1*15+3)*15+10)*15+11,查看源码可以知道为什么?

还有就是第二个形参,函数希望你传递给它的是一个指针变量的地址。我们可以这么想,第一个函数的形参是char * string ,所以传递给的是一个指针(地址),所以这样调用:char *string;atoi(string),string的值是存放在该地址(具体是哪个编译器决定)的值,即是它指向的变量的地址。以此类推,第三个函数的第二个形参需要的是指针变量的地址,既然这样,我们就需要的是string这个名字的内存地址所在,因为string是指针变量,地址那就是&string这个值了!!!!!!!懂不???YES!以后遇到这种形参就会填写了!记住了!建议不懂可以画个调用图。以下是例子程序,里面便有如上所说的情况:

#include <stdlib.h>

#include <stdio.h>

void third_ptr(char ***string);

void fourth_ptr(char ****string);

void main(void)

{

int atoi_ret;

long int atol_ret,strtol_ret;

char *ptr=NULL;

unsigned long strtoul_ret;

const char *atoi_str="89";

atoi_ret=atoi(atoi_str);

printf("atoi_ret=%d\n",atoi_ret);

const char *atol_str="901";

atol_ret=atol(atol_str);

printf("atol_ret=%d\n",atol_ret);

const char *strtol_str=" aft?pl";

strtol_ret=strtol(strtol_str,&ptr,16);

printf("strtol_ret=%d,unused=%s\n",strtol_ret,ptr);

//printf("unused=%d\n",unused);

const char *strtoul_str="ab::i";

strtoul_ret=strtoul(strtoul_str,NULL,20);

printf("strtoul_ret=%d\n",strtoul_ret);

char *str=NULL;

char **str1;

str1=&str;

third_ptr(&str1);

printf("str=%s\n",str);

char *str2=NULL;

char **str3;

str3=&str2;

char ***str4;

str4=&str3;

fourth_ptr(&str4);

printf("str4=%s\n",str2);//this str2 is the first ptr in this relation!we get this complex

// relationship step by step

}

void third_ptr(char ***string)

{

char *str="according to this test program,we can understand the multiptr well!";

**string=str;

}

void fourth_ptr(char ****string)

{

char *str="test again!";

***string=str;

}

函数13、断言函数:assert(int expression),很有用的!!再次不再说了。

到此结束,还有一些不常用的不说了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: