网络编程-socket

看到这篇文章写得挺清楚 就贴过来了
http://8-1.myrice.com/study/linux/linux.htm
*******************************************************


好了,我们开始吧,Socket,你一定很熟悉Socket这个词,无论是在windows还是linux,
只要你要telnet主机,或是用ftp上传文件到服务器,又或是用浏览器看网页,就一定会
用到他。
如果你是新手,你到这里来,已经走到了socket编程的第一步。假设你已经有C语言编
程的基础,我不想在这里多谈C语言

----------------------------------

既使你知道Socket这个词,既使你常听到人们谈到“Socket”,而你却不知道其确切含义
。其实他是使用文件描述符 和其他程序通讯的方式。

OK,在UNIX里,所有的东西都是文件,你的CDROM是文件,你的显示器是文件,
你的硬盘也是文件你的。。。也是文件。。。所以,你想和网络上其他程序通信的时
候就要通过文件描述符。那是真的,请你相信,我决不骗你。

现在你或许会想:我该怎么样得到网络通讯的文件描述符呢?你就要用到系统调用
socket(),他返回套接口文件描述符,然后你可以把这个文件描述符当作普通的文件来
操作,不过最好使用send()和recv(),这样比较好点,好处以后再说!

在internet上有多种套接口,不用惊奇,也不要感到害怕,因为常用的套接口只有两种
,那就是流式套接品和数据报套接口,而我这里要讲的只是流式套接口,对于数据报

接口只作简单的介绍。如果理解了流式套接口,其他的也就简单了。因为他们都是套接
口!

流式套接口可以提供可靠的双向通讯数据流,他们也是无错误的传递,在TCP里有自已
的错误控制。
使用流式套接口的例子很多,至少你的浏览器就在用!因为浏览其实就是telnet到主机的
80端口get页面,然后你可爱的netscapt或ie就可以看到网页html的内容了!
因为流式套接口使用的是传输控制协议(TCP)所以数据可以按顺序,到达并且不会出
错。或许你听说过TCP/IP,这里的IP指的是Internet协议,他用来处理Internet路由。
而数据报套接口可以提供更快的传输速率,但却是不可靠的。举个例子,你传送一组数
据123456789,可能到达时,他的次序已经乱了,可能是987456321了不过你可以放心,
IP路由会为你处理这个问题,他不使用TCP,而是使用UDP,一种叫“用户数据包协议”
的怪异东东,而且怪异到不用维持一个连接就能发送数据。只要数据包里构造一个IP头
,IP头里包括你要发送到的目的地信息。

“STOP!”你也许会被那些怪异的事搞的发疯,或许你还是无法理解什么是套接口,好吧
,让我们从一个程序开始吧!


 
Linux Socket 网络编程(二)

好了,现在我来解释一个前次的程序;


#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
这些是必要和头文件

#define PORT 4567
#define BUFSIZE 512
常量定义,假设端口为4567,缓冲为512字节

int main(int argc,char** argv)
这就不用我解释了吧:)如果真不知道,去翻翻有关C语言的书吧!

{
int socketf,n;
char buf[BUFSIZE];
struct sockaddr_in server;

有必要解释一下sockaddr_in
这是一个internet 套接口结构,
struct in_addr {
in_addr_t s_addr; /* 32位IPV4地址 */
};

struct sockaddr_in {
short int sin_family; /* 地址族 */
unsigned short int sin_port; /* 端口 */
struct in_addr sin_addr; /* internet地址(32位IPV4) */
unsigned char sin_zero[8]; /* 不知道什么用,反正没用到过 */
};

对于sin_family,我们一般都填AF_INET,当然还有其他的,我们一般现在用的都还是
IPV4,如果你要用IPV6,这个就是AF_INET6啦!只是多加了一个6,就把32位IP地址变

成了128位,这个世界真是神奇(当然你还要做很多事)

sin_port是你的端口号,看到了吧,是16位的,所以端口号不会大于
0xffff啦;要注意的是
要把它转换成网络字节序,这就要用到以下四个函数了:

htons()
htonl()
ntohs()
ntohl()

是不是有些眼花了,这四个函数好像很像啊!对了,其实他们都是做同样的事,只是分
工不同
htons把16位本地字节序转换成16位网络字节序,ntohs刚好相反
htonl把32位本地字节序转换成32位网络字节序,ntohl刚好相反
告诉你们一个诀窍,这里的h代表host,n代表network,s代表short(16位),l代表long(32位)
这样是不是好记了点?只要你懂得英语里"to"这个单词的含义就行了!

好了,看看我们的IP地址,是in_addr结构.再深入一步看in_addr结构,
里面有
in_addr_t s_addr;
这里的in_addr_t其实就是unsigned int,不要被它的样子吓坏,其实它很可爱:)
所以我们填写IP地址的时候就要
...
struct sockaddr_in server;
...
server.sin_addr.s_addr=inet_addr("192.168.0.1");
inet_addr()可以把你的点分十进制IP地址变为计算机认识的IP地址;
仔细的人可能以经看出,我这里没有用htonl(),那是因为inet_addr已经把IP地址转换为
网络字节序了!真是聪明!噢,我指的是inet_addr()很聪明!


至于sin_zero[8];一般都是把它清空为0,不过为了方便,在初始化的时候把整个结构清
空;我们可以用bzero()和memset()不过用bzero更方便点,memset()功能更强大点,不过在
这里这两个都一样,我们就用bzero了!

OK,整个结构都说完了,现在回到我们的程序去吧!


if(argc!=2)
{
printf("%s","IP address error");
exit(-1);
}

当然,你不输入IP地址,你的程序当然不知道要连接到哪儿去啊!

if((socketf=socket(AF_INET,SOCK_STREAM,0)<=0)
{
printf("%s","socket error");
exit(-1);
}
这又是什么?socket()?哦,我忘了解释套接口描述字了!
还记得我以前说过,在UNIX里,什么东西都是文件吗?对,套接口也是文件,所以
也要用文件描述符,只是这里是套接口描述符而已,其实都差不多。
上面socketf=socket(AF_INET,SOCK_STREAM,0)就是为了得到这个套接口描述符。
AF_INET是必须的,如果用到的是IPV6这里就是AF_INET6了,SOCK_STREAM指明是
流式套接口,而不是数据报套接口(其实套接口的种类远不指这些,只是不想让大家多伤
脑细胞而已)。最后一个一定要填0,可能是为以后着想的吧!


bzero(&server,sizeof(server));
还记得这个bzero吗?我在前面说过的!对,把结构清空!为了方便,我们把整个结
构清空了!

server.sin_family = AF_INET;
server.port = htons(PORT);
server.sin_addr.s_addr=inet_addr(argv[1]);

好,填写套接口结构。看清最后一行了吗?怎么填IP地址。不过这里有个错误,因
为inet_addr在出错时返回-1,-1是什么?记得0xffffffff吗?这是什么?把它翻成点分
十进制吧,那就是255.255.255.255,这就是internet广播地址。0xffffffff第一位是符号
位,所以也是-1。真是历害,一出错就发广播了,是不是怕天下人不知道啊?

if(connetc(socketf,(struct sockaddr *)&server,sizeof(server))<0)
{
printf("%s","connetc error");
exit(-1);
}
得到了socketf,我们就可以连接了,这就要用到connetc了!
是不是该解释一个这个函数了?OK!第一个参数是套接口描述字,就是要连接上哪
个套接口。第二个是一个套接口结构地址指针,我们这里是server,当然要数据转换了,
因为一个是sockaddr,一个是sockaddr_in,虽然这两个其实差不多,不过转换还是必要的。

还是不明白?算了,还是好人做到底,把sockaddr这个结构也解释一下吧!
struct sockaddr {
unsigned short sa_family; /* 地族,当然也是 AF_xxx */
char sa_data[14]; /* 14 bytes 协议地址 */
};
啊,和我们的sockaddr_in差不多嘛,我没骗你吧,只是把sa_data[14]分得更小更多我们
把sockaddr_in里除了sa_family外其他的加起来,也刚好是14
bytes耶!如果有兴趣,
你也可以用sockaddr代替sockaddr_in,当然在实际编程中恐怕。。。很少或几乎是没
有人会这样做的吧!

好了,让我们回到connect吧,还有最后一个参数,说明要连接对向的大小,我们这
里是server大小~!
当然,如果连接出错我们就exit(-1);闪人喽~!


if(recv(socketf,buf,BUFSIZE,0)<0)
{
prinft("%s","recever error");
exit(-1);
}
else
printf("%s",buf);
recv(),接收数据,我这里就不发送了,从socketf接受BUFSIZE个字节的数据到buf里去;


close(socketf);

文件用完要关闭,套接口也是一样,要close(socketf);

}
最后不要忘了关门
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值