用C语言编写Socket程序.docx

上传人:b****8 文档编号:30462725 上传时间:2023-08-15 格式:DOCX 页数:42 大小:29KB
下载 相关 举报
用C语言编写Socket程序.docx_第1页
第1页 / 共42页
用C语言编写Socket程序.docx_第2页
第2页 / 共42页
用C语言编写Socket程序.docx_第3页
第3页 / 共42页
用C语言编写Socket程序.docx_第4页
第4页 / 共42页
用C语言编写Socket程序.docx_第5页
第5页 / 共42页
点击查看更多>>
下载资源
资源描述

用C语言编写Socket程序.docx

《用C语言编写Socket程序.docx》由会员分享,可在线阅读,更多相关《用C语言编写Socket程序.docx(42页珍藏版)》请在冰豆网上搜索。

用C语言编写Socket程序.docx

用C语言编写Socket程序

用C语言编写Socket程序

本文的目的在于为初学者提供一个快速的入门指导,用来迅速熟悉用C语言来编写

Internet网络应用程序。

本文假设读者已经具备了C语言的基本知识和语法,并且

读者有使用Uinx/Linux的经验。

尽管Uinx/Linux的Socket编程与在Windows下的有

一些不同的地方,但是在此我并不想展开。

另外,本文所有的程序都在RedHat

5.2下编译通过,并且在glibc2.0.7和libc5.3.12两种环境下都没有问题。

现在

就开始我们的教程吧:

)。

对一个程序员而言,sockets和底层的文件描述符非常类似(可以在sockets里使

用read()和write()函数),尽管建立一个socket比打开,读取和写入一个文件更

为麻烦,但这是由于网络连接比单纯的本地硬盘的读写复杂的多所造成的。

通常,sockets用来实现客户机/服务器对。

服务器的任务是监听某个特定的端口

,当接收到客户端的服务请求时完成相应的服务;客户机的任务是请求服务器完

成事先设定好的服务。

作为入门级的文章,我们在这里不会使用所有的socket类型和功能,但是我们会

向读者提供足够的信息。

现在,就让我们开始吧。

=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==

+==+==+=

建立一个socket:

socket()

你所要学的socket编程的第一件事就是用socket()建立一个socket:

--------

#include

#include

intsocket(intaf,inttype,intprotocol)

-------

'intaf'代表地址族或者称为socket所代表的域,通常有两个选项:

    AF_UNIX-只在单机上使用。

    AF_INET-可以在单机或其他使用DARPA协议(UDP/TCP/IP)的异种机通信。

'inttype'代表你所使用的连接类型,通常也有两种情况:

    SOCK_STREAM-用来建立面向连接的sockets,可以进行可靠无误的的数据传

    SOCK_DGRAM-用来建立没有连接的sockets,不能保证数据传输的可靠性。

在本文中,我们着重使用AF_INET地址族和SOCK_STREAM连接类型。

'intprotocol'通常设定为0。

这样的目的是使系统选择默认的由协议族和连接类

型所确定的协议。

这个函数的返回值是一个文件描述句柄,如果在此期间发生错误则返回-1并且设

定了相应的errno。

-------

#include

#include

intsockfd/*soontobesocketfiledescriptor*/

sockfd=socket(AF_INET,SOCK_STREAM,0)

/*errorcheckinghere*/

-------

如果执行成功,我们就拥有了一个socket的文件句柄,通过这个句柄就可以访问

Internet了。

=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==

+==+==+=

名字绑定socket:

bind()

下一步要完成的就是名字绑定工作了:

-------

#include

#include

intbind(intsockfd,structsockaddr*name,intnamelen)

-------

在这个函数里,sockfd是从socket()调用得到的文件描述句柄。

name是一个指向

sockaddr类型结构的一个指针。

如果地址族被设定为AF_UNIX,这个类型的定义是

如下所示:

-------

structsockaddr{

u_shortsa_family;

charsa_data[14];

};

-------

在这个结构种,name.sa_family应当被设定为AF_UNIX。

name.sa_data应当包含最

长为14个字节的文件名,这个文件名用来分配给socket。

namelen给出了文件名的

具体长度。

-------

#include

#include

structsockaddrname;

intsockfd;

name.sa_family=AF_UNIX;

strcpy(name.sa_data,"/tmp/whatever");

sockfd=socket(AF_UNIX,SOCK_STREAM,0)

/*errorcheckingcodehere*/

bind(sockfd,&name,strlen(name.sa_data)+sizeof(name.sa_family)

/*errorcheckingcodehere*/

-------

如果调用成功,则返回值为0,如果调用失败返回值为-1,并设定相应的错误代码

errno。

现在,让我们在使用另一种结构,它是在使用AF_INET地址族的时候使用的。

------

structsockaddr_in{

shortintsin_family;/*Addressfamily*/

unsignedshortintsin_port;/*Portnumber*/

structin_addrsin_addr;/*Internetaddress*/

unsignedcharsin_zero[8];/*Samesizeasstructsockaddr*/

};

-------

看起来它比前一个大多了,但要掌握它并不十分困难。

-------

#include

#include

#include

#include

intsockfd,port=23;

structsockaddr_inmy_addr;

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

{

printf("SocketError,%d\n",errno);

exit

(1);

}

my_addr.sin_family=AF_INET;/*hostbyteorder*/

my_addr.sin_port=htons(port);/*seemanhtonsformoreinformation

*/

my_addr.sin_addr.s_addr=htonl(INADDR_ANY);/*getouraddress*/

bzero(&(my_addr.sin_zero),8);/*zeroouttherestofthespace*/

if((bind(sockfd,(structsockaddr*)&my_addr,sizeof(structsockaddr))

==-1)

{

printf("BindError,%d\n",errno);

close(sockfd);

exit

(1);

}

-------

现在,如果没有问题的话,我们建立的socket就有一个名字了!

相反,如果不成

功,它会设定相应的错误代码,并使程序退出。

这里需要说明的是,如果你的计

算机不想和别人的计算机连接,那么完全没有必要使用bind()。

对于端口的绑定

,在服务器而言是不合适的,它只应该在客户机上实现。

=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==

+==+==+=

远程连接:

connect()

这是和别的计算机连接所必须的一步。

-------

#include

#include

intconnect(intsockfd,structsockaddr*serv_addr,intaddrlen);

-------

sockfd是我们建立的文件描述句柄,serv_addr是一个sockaddr结构,包含目的的

地址和端口号,addrlen被设定为sockaddr结构的大小。

-------

#include

#include

#include

#defineDEST_IP"132.241.5.10"

#defineDEST_PORT23

main()

{

intsockfd;

structsockaddr_indest_addr;/*willholdthedestinationaddr*/

sockfd=socket(AF_INET,SOCK_STREAM,0);/*dosomeerrorchecking!

*

/

dest_addr.sin_family=AF_INET;/*hostbyteorder*/

dest_addr.sin_port=htons(DEST_PORT);/*short,networkbyteorder*/

dest_addr.sin_addr.s_addr=inet_addr(DEST_IP);

bzero(&(dest_addr.sin_zero),8);/*zerotherestofthestruct*/

connect(sockfd,(structsockaddr*)&dest_addr,sizeof(structsockaddr)

);

/*errorcheckingcodehere*/

/*morecode

.

.

.

*/

}

-------

同样,connect()在调用返回后,如果返回值为0则表明成功,如果是1则说明有错

误,并且同时设定了相应的错误代码。

由于我们现在不关心具体和那个端口连接

,所以在上面的例程里我们没有调用了bind()函数。

=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==

+==+==+=

监听:

listen()

当我们需要建立一个服务器的时候,我们需要有一种手段来监听输入的请求,而

listen()函数正是提供这个功能。

-------

#include

#include

intlisten(intsockfd,intbacklog);

-------

参数backlog是指一次可以监听多少个连接

它的调用返回结果和上述的几个函数是一样的,这里就不多说了。

值得一提的是,在这里,我们需要建立一个绑定,用来接收特定端口的服务请求

-------

socket();/*tocreateoutsocketfiledescriptor*/

bind();/*togiveoursocketaname*/

listen();/*listenforconnection*/

-------

=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==

+==+==+=

接受连接:

accept()

好了,现在开始实质性的工作了。

当有人试图从我们打开的端口登陆进来时我们

应该响应他,这个时候就要用到accept()函数了。

-------

#include

#include

intaccept(intsockfd,void*addr,int*addrlen);

-------

函数调用所需的参数都是我们所熟悉的:

-------

#include

#include

#include

#defineMYPORT1500/*theportuserswillbeconnectingto*/

#defineBACKLOG5/*howmanypendingconnectionsqueuewillhold*/

main()

{

intsockfd,new_fd;/*listenonsock_fd,newconnectiononnew_fd*/

structsockaddr_inmy_addr;/*myaddressinformation*/

structsockaddr_intheir_addr;/*connector'saddressinformation*/

intsin_size;

sockfd=socket(AF_INET,SOCK_STREAM,0);/*dosomeerrorchecking!

*

/

my_addr.sin_family=AF_INET;/*hostbyteorder*/

my_addr.sin_port=htons(MYPORT);/*short,networkbyteorder*/

my_addr.sin_addr.s_addr=INADDR_ANY;/*auto-fillwithmyIP*/

bzero(&(my_addr.sin_zero),8);/*zerotherestofthestruct*/

/*didyourememberyourerrorchecking?

*/

bind(sockfd,(structsockaddr*)&my_addr,sizeof(structsockaddr));

listen(sockfd,BACKLOG);

sin_size=sizeof(structsockaddr_in);

new_fd=accept(sockfd,&their_addr,&sin_size);

-------

这里我们要注意的是:

我们用new_fd来完成所有的接收和发送的操作。

如果在只

有一个连接的情况下你可以关闭原来的sockfd用来防止更多的输入请求。

=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==

+==+==+=

输入和输入的完成:

send()andrecv()

在我们完成了上述的工作后,最后一步就是传输数据了:

)。

在这里,我们通过se

nd()和recv()来实现。

-------

#include

#include

intsend(intsockfd,constvoid*msg,intlen,intflags);

intrecv(intsockfd,void*buf,intlen,unsignedintflags);

-------

send():

sockfd-socketfiledescriptor

msg-messagetosend

len-sizeofmessagetosend

flags-read'mansend'formoreinfo,setitto0fornow:

recv():

sockfd-socketfiledescriptor

buf-datatoreceive

len-sizeofbuf

flags-sameasflagsinsend()

send()例程:

-------

char*msg="Heytherepeople";

intlen,send_msg;

/*codetocreate(),bind(),listen()andaccept()*/

len=strlen(msg);

bytes_sent=send(sockfd,msg,len,0);

-------

recv()例程:

-------

char*buf;

intlen,recv_msg;

/*codetocreate(),bind(),listen()andaccept()*/

len=strlen(buf);

recv_msg=recv(sockfd,buf,len,0);

-------

如果你使用的连接类型是SOCK_DGRAM,那么应该使用sendto()和recvfrom()来实

现数据传输。

=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==

+==+==+=

最后一步:

close()andshutdown()

当传输结束时,应当关闭连接。

-------

#include

/*allyoucode*/

close(sockfd);

-------

更保险的方法是用shutdown()来关闭连接。

-------

intshutdown(intsockfd,inthow)

-------

参数how的选择:

1-不允许接收更多的数据

2-不允许发送更多的数据

3-不允许接收和发送更多的数据(和close()一样)

一切就是这么简单:

=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==

+==+==+=

你是谁:

getpeerbyname()

可能你还想知道是谁正在和你连接,那么看下面:

-------

#include

intgetpeername(intsockfd,structsockaddr*addr,int*addrlen);

-------

参数addr是一个指向'structsockaddr'或者'structsockaddr_in'的指针。

如果执行成功,我们就得到了对方的地址了,然后用inet_ntoa()用gethostbyad

dr()来得到对方更多的信息。

如果还想知道更多的,请参阅RFC1413。

=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==

+==+==+=

我是谁:

gethostname()

-------

#include

intgethostname(char*hostname,size_tsize);

-------

hostname是一个存放主机名字的字符数组

返回的hostname可以作为gethostbyname()的参数,这样又可以得到自己的IP地址

了。

=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==

+==+==+=

我的IP是多少?

现在把我们所学的集中起来,逐步就可以完成一个实用的程序了。

还是来研究一

下如下的情况:

$telnet

Trying206.163.24.176(nottherealaddressbutI'mtoolazytotry:

我们看到,telnet程序所做的第一件事情是域名解析!

这个工作是由gethostbyn

ame()完成的。

-------

#include

structhostent*gethostbyname(constchar*name);

-------

一个特殊的结构hostent:

-------

structhostent{

char*h_name;

char**h_aliases;

inth_addrtype;

inth_length;

char**h_addr_list;

};

#defineh_addrh_addr_list[0]

-------

这个结构可以被分为:

h_name-正式的机器名

h_aliases-一个以NULL结尾的字符串,表示机器的别名。

h_addrtype-地址所使用的类型,通常是AF_INET。

h_length-用字节数表示的地址长度。

h_addr_list-一个以0结尾的数组,表示机器的网络地址,以网络的字节顺序排

列。

h_addr-在h_addr_list里的第一个地址。

gethostbyname()返回一个指向hostent结构的指针或者是一个NULL指针表示错误

(尽管如此,错误代码没有设定!

)。

现在我们就来完成我们的DNS程序:

-------

#include

#include

#include

#include

#include

#include

intmain(intargc,char*argv[])

{

structhostent*h;

if(argc!

=2){/*errorcheckingonthecommandline*/

fprintf(stderr,"Usage:

getip\n");

exit

(1);

}

if((h=gethostbyname(argv[1]))==NULL){/*getthehostinfo*/

herror("gethostbyname");

exit

(1);

}

printf("Hostname:

%s\n",h->h_name);

printf("IPAddres

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 小学教育 > 小学作文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1