ImageVerifierCode 换一换
格式:DOCX , 页数:42 ,大小:29KB ,
资源ID:30462725      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/30462725.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(用C语言编写Socket程序.docx)为本站会员(b****8)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

用C语言编写Socket程序.docx

1、用C语言编写Socket程序用C语言编写Socket程序本文的目的在于为初学者提供一个快速的入门指导,用来迅速熟悉用C语言来编写Internet网络应用程序。本文假设读者已经具备了C语言的基本知识和语法,并且读者有使用Uinx/Linux的经验。尽管Uinx/Linux的Socket编程与在Windows下的有一些不同的地方,但是在此我并不想展开。另外,本文所有的程序都在Red Hat 5.2下编译通过,并且在glibc 2.0.7和libc 5.3.12两种环境下都没有问题。现在就开始我们的教程吧:)。对一个程序员而言,sockets和底层的文件描述符非常类似(可以在sockets里使用re

2、ad()和write()函数),尽管建立一个socket比打开,读取和写入一个文件更为麻烦,但这是由于网络连接比单纯的本地硬盘的读写复杂的多所造成的。通常,sockets用来实现客户机/服务器对。服务器的任务是监听某个特定的端口,当接收到客户端的服务请求时完成相应的服务;客户机的任务是请求服务器完成事先设定好的服务。作为入门级的文章,我们在这里不会使用所有的socket类型和功能,但是我们会向读者提供足够的信息。现在,就让我们开始吧。=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=建立一个socket:socket()你所要学的sock

3、et编程的第一件事就是用socket()建立一个socket:- -#include #include int socket(int af, int type, int protocol)- -int af代表地址族或者称为socket所代表的域,通常有两个选项: AF_UNIX - 只在单机上使用。 AF_INET - 可以在单机或其他使用DARPA协议(UDP/TCP/IP)的异种机通信。int type代表你所使用的连接类型,通常也有两种情况: SOCK_STREAM - 用来建立面向连接的sockets,可以进行可靠无误的的数据传输 SOCK_DGRAM - 用来建立没有连接的sock

4、ets,不能保证数据传输的可靠性。在本文中,我们着重使用AF_INET地址族和SOCK_STREAM连接类型。int protocol通常设定为0。这样的目的是使系统选择默认的由协议族和连接类型所确定的协议。这个函数的返回值是一个文件描述句柄,如果在此期间发生错误则返回-1并且设定了相应的errno。- -#include #include int sockfd /* soon to be socket file descriptor */sockfd = socket(AF_INET, SOCK_STREAM, 0)/* error checking here */- -如果执行成功,我们就

5、拥有了一个socket的文件句柄,通过这个句柄就可以访问Internet了。=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=名字绑定socket: bind()下一步要完成的就是名字绑定工作了:- -#include #include int bind(int sockfd, struct sockaddr *name, int namelen)- -在这个函数里,sockfd是从socket()调用得到的文件描述句柄。name是一个指向sockaddr类型结构的一个指针。如果地址族被设定为AF_UNIX,这个类型的定义是如下所示:-

6、-struct sockaddr u_short sa_family;char sa_data14;- -在这个结构种,name.sa_family应当被设定为AF_UNIX。name.sa_data应当包含最长为14个字节的文件名,这个文件名用来分配给socket。namelen给出了文件名的具体长度。- -#include #include struct sockaddr name;int sockfd;name.sa_family = AF_UNIX;strcpy(name.sa_data, /tmp/whatever);sockfd = socket(AF_UNIX, SOCK_STR

7、EAM, 0)/* error checking code here */bind(sockfd, &name, strlen(name.sa_data) + sizeof(name.sa_family)/* error checking code here */- -如果调用成功,则返回值为0,如果调用失败返回值为-1,并设定相应的错误代码errno。现在,让我们在使用另一种结构,它是在使用AF_INET地址族的时候使用的。- -struct sockaddr_in short int sin_family; /* Address family */unsigned short int si

8、n_port; /* Port number */struct in_addr sin_addr; /* Internet address */unsigned char sin_zero8; /* Same size as struct sockaddr */;- -看起来它比前一个大多了,但要掌握它并不十分困难。- -#include #include #include #include int sockfd, port = 23;struct sockaddr_in my_addr;if(sockfd=socket(AF_INET, SOCK_STREAM, 0) = -1)printf

9、(Socket Error, %dn, errno);exit(1);my_addr.sin_family = AF_INET; /* host byte order */my_addr.sin_port = htons(port); /* see man htons for more information */my_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* get our address */bzero(&(my_addr.sin_zero), 8); /* zero out the rest of the space */if(bind(s

10、ockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)= -1)printf(Bind Error, %dn, errno);close(sockfd);exit(1);- -现在,如果没有问题的话,我们建立的socket就有一个名字了!相反,如果不成功,它会设定相应的错误代码,并使程序退出。这里需要说明的是,如果你的计算机不想和别人的计算机连接,那么完全没有必要使用bind()。对于端口的绑定,在服务器而言是不合适的,它只应该在客户机上实现。=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

11、=+=+=+=+=远程连接: connect()这是和别的计算机连接所必须的一步。- -#include #include int connect(int sockfd, struct sockaddr *serv_addr, int addrlen); - -sockfd是我们建立的文件描述句柄,serv_addr是一个sockaddr结构,包含目的的地址和端口号,addrlen 被设定为sockaddr结构的大小。- -#include #include #include #define DEST_IP 132.241.5.10#define DEST_PORT 23main()int s

12、ockfd;struct sockaddr_in dest_addr; /* will hold the destination addr */sockfd = socket(AF_INET, SOCK_STREAM, 0); /* do some error checking! */dest_addr.sin_family = AF_INET; /* host byte order */dest_addr.sin_port = htons(DEST_PORT); /* short, network byte order */dest_addr.sin_addr.s_addr = inet_a

13、ddr(DEST_IP);bzero(&(dest_addr.sin_zero), 8); /* zero the rest of the struct */connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr);/* error checking code here */* more code .*/- -同样,connect()在调用返回后,如果返回值为0则表明成功,如果是1则说明有错误,并且同时设定了相应的错误代码。由于我们现在不关心具体和那个端口连接,所以在上面的例程里我们没有调用了bind()函数。

14、=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=监听: listen()当我们需要建立一个服务器的时候,我们需要有一种手段来监听输入的请求,而listen()函数正是提供这个功能。- -#include #include int listen(int sockfd, int backlog);- -参数backlog是指一次可以监听多少个连接它的调用返回结果和上述的几个函数是一样的,这里就不多说了。值得一提的是,在这里,我们需要建立一个绑定,用来接收特定端口的服务请求。- -socket(); /* to create out sock

15、et file descriptor */bind(); /* to give our socket a name */listen(); /* listen for connection */- -=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=接受连接: accept()好了,现在开始实质性的工作了。当有人试图从我们打开的端口登陆进来时我们应该响应他,这个时候就要用到accept()函数了。- -#include #include int accept(int sockfd, void *addr, int *addrlen);-

16、-函数调用所需的参数都是我们所熟悉的:)- -#include #include #include #define MYPORT 1500 /* the port users will be connecting to */#define BACKLOG 5 /* how many pending connections queue will hold */main()int sockfd, new_fd; /* listen on sock_fd, new connection on new_fd */struct sockaddr_in my_addr; /* my address inf

17、ormation */struct sockaddr_in their_addr; /* connectors address information */int sin_size;sockfd = socket(AF_INET, SOCK_STREAM, 0); /* do some error checking! */my_addr.sin_family = AF_INET; /* host byte order */my_addr.sin_port = htons(MYPORT); /* short, network byte order */my_addr.sin_addr.s_add

18、r = INADDR_ANY; /* auto-fill with my IP */bzero(&(my_addr.sin_zero), 8); /* zero the rest of the struct */* did you remember your error checking? */bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr);listen(sockfd, BACKLOG);sin_size = sizeof(struct sockaddr_in);new_fd = accept(sockfd,

19、&their_addr, &sin_size);- -这里我们要注意的是:我们用new_fd来完成所有的接收和发送的操作。如果在只有一个连接的情况下你可以关闭原来的sockfd用来防止更多的输入请求。=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=输入和输入的完成: send() and recv()在我们完成了上述的工作后,最后一步就是传输数据了:)。在这里,我们通过send()和recv()来实现。- -#include #include int send(int sockfd, const void *msg, int len,

20、int flags);int recv(int sockfd, void *buf, int len, unsigned int flags);- -send():sockfd - socket file descriptormsg - message to sendlen - size of message to sendflags - read man send for more info, set it to 0 for now :)recv():sockfd - socket file descriptorbuf - data to receivelen - size of buffl

21、ags - same as flags in send()send() 例程:- -char *msg = Hey there people;int len, send_msg;/* code to create(), bind(), listen() and accept() */ len = strlen(msg);bytes_sent = send(sockfd, msg, len, 0);- -recv() 例程:- -char *buf;int len, recv_msg;/* code to create(), bind(), listen() and accept() */len

22、 = strlen(buf);recv_msg = recv(sockfd, buf, len, 0);- -如果你使用的连接类型是SOCK_DGRAM,那么应该使用sendto()和recvfrom()来实现数据传输。=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=最后一步: close() and shutdown()当传输结束时,应当关闭连接。- -#include /* all you code */close(sockfd);- -更保险的方法是用shutdown()来关闭连接。- -int shutdown(int sock

23、fd, int how)- -参数how的选择:1 - 不允许接收更多的数据2 - 不允许发送更多的数据3 - 不允许接收和发送更多的数据(和close()一样)一切就是这么简单:)=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=你是谁: getpeerbyname()可能你还想知道是谁正在和你连接,那么看下面:- -#include int getpeername(int sockfd, struct sockaddr *addr, int *addrlen);- -参数addr是一个指向struct sockaddr或者struct

24、 sockaddr_in的指针。如果执行成功,我们就得到了对方的地址了,然后用inet_ntoa()用gethostbyaddr()来得到对方更多的信息。如果还想知道更多的,请参阅RFC 1413。=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=我是谁: gethostname()- -#include int gethostname(char *hostname, size_t size);- -hostname是一个存放主机名字的字符数组返回的hostname可以作为gethostbyname()的参数,这样又可以得到自己的IP地址

25、了。=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=我的IP是多少? 现在把我们所学的集中起来,逐步就可以完成一个实用的程序了。还是来研究一下如下的情况:$ telnet Trying 206.163.24.176 (not the real address but Im too lazy to try :)我们看到,telnet程序所做的第一件事情是域名解析!这个工作是由gethostbyname()完成的。- -#include struct hostent *gethostbyname(const char *name);- -一

26、个特殊的结构hostent:- -struct hostent char *h_name;char *h_aliases;int h_addrtype;int h_length;char *h_addr_list;#define h_addr h_addr_list0- -这个结构可以被分为:h_name - 正式的机器名h_aliases - 一个以NULL结尾的字符串,表示机器的别名。 h_addrtype - 地址所使用的类型,通常是AF_INET。 h_length - 用字节数表示的地址长度。h_addr_list - 一个以0结尾的数组,表示机器的网络地址,以网络的字节顺序排列。

27、h_addr - 在h_addr_list里的第一个地址。gethostbyname()返回一个指向hostent结构的指针或者是一个NULL指针表示错误(尽管如此,错误代码没有设定!)。现在我们就来完成我们的DNS程序:- -#include #include #include #include #include #include int main(int argc, char *argv)struct hostent *h;if (argc != 2) /* error checking on the command line */fprintf(stderr,Usage: getip n);exit(1);if (h=gethostbyname(argv1) = NULL) /* get the host info */herror(gethostbyname);exit(1);printf(Host name : %sn, h-h_name);printf(IP Addres

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

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