免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5247 | 回复: 0
打印 上一主题 下一主题

[SCO UNIX] UNIX系统TCP/IP Socket接口的应用 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2003-02-14 14:35 |显示全部楼层 |倒序浏览
UNIX系统TCP/IP Socket接口的应用

  Socket接口是TCP/IP网络的API(应用程序接口)。它定义了许多函数和例程,程序员可以用它开发TCP/IP网络上的应用程序,可以在CLIENT/SERVER模型中制作自己的应用程序通信接口。今天,Socket接口是TCP/IP网络最为通用的API之一。
TCP/IP协议组可以实现面向连接和无连接两种网络通信。面向连接的协议在两个连接端点之间建立一条虚电路,两个端点之间的链路可以看作是直接的点到点的连接。两个端点只有在建立连接后才能传输数据。在面向连接的网络通信中,数据按字节流形式传输。无连接协议在传输报文前,不用建立连接。无连接协议每个报文包含一个完整,精确的传送地址。在无连接网络通讯中,数据按数据包形式流动。网络通信包含两台主机或两个进程,网络对话的每一端称为一个端点。可将Socket看作网络通信的一个端点,当使用Socket接口对网络通信编程时,Socket是网络通信过程中端点的抽象表示。程序在网络对话的每端都需要先建立一个Socket,即为一个Socket数据结构分配存储空间。

图1,图2是面向连接的和无连接的Socket使用综述图。

图1 面向连接协议时socket的使用

图2 无连接协议时socket的使用

一.系统调用说明:??

有关消息队列的系统调用均需下列头文件:

#include <sys/types.h>;

#include <sys/socket.h>;

#include <arpa/inet.h>;

#include <netinet/in.h>;

#include <fcntl.h>;

1。socket 调用

建立一个socket,即为一个socket数据结构分配存储空间。并初步定义socket的属性。调用格式如下:

int s, domain, type, protocol;

s = socket (domain, type, protocol);

domain:协议族和地址族,确定socket使用的一组协议。与三个符号常数有关:

PF_INET 表示互联网协议族,一般选用此参数。

PF_VNIX 表示VNIX内部协议族。

PF_NS 表示Xerox网络服务协议族。

type:通信类型,与两个符号常数有关:

SOCK_STREAM 以字节流形式通信,面向连接的协议使用这种形式。

SOCK_DGRAM 数据以独立的数据包形式流动,无连接协议使用这种形式。

protocol:指明此socket请求使用的协议,可以使用相关符号常数来表示:

IPPROTO_TCP 表示TCP协议。

IPPROTO_UDP 表示UDP协议。

s:如调用成功,返回socket描述符。否则返回-1。

2。connect调用

启动和远地主机的直接连接,只有面向连接的客户程序使用此函数。调用格式如下:

int s, namelen;

struct sockaddr *name;

int connect (s, name, namelen);

s: socket句柄,是socket函数返回的socket描述符。

name: 远地socket地址,是一个指向特定socket地址结构的指针。此结构保存了一个地址族,一个协议端口和一个网络主机地址。

namelen: 地址长度,简单地告诉socket执行体远地socket地址结构(第二个参数)按字节的大小。

返回值: 连接成功返回0,不成功返回-1。

3。bind调用

配置一个socket的本地地址(包括主机地址和协议端口)。指明socket将使用本地的哪一个协议端口进行数据传送。面向连接的服务器程序,无连接的服务器程序,无连接的客户程序使用此函数。调用格式如下:

int s, namelen;

struct sockaddr *name;

int bind (s, name, namelen);

s: socket句柄,socket函数返回的socket描述符。

name: 本地socket地址,是指向特定socket地址结构的指针。指明用于通信的本地协议端口。

namelen: 本地socket地址结构的长度。

返回值: 调用成功返回0,不成功返回-1。

4。listen调用

建立一个输入数据队列,将到达本地的客户服务请求保存在此队列上,直到程序处理它们。面向连接的服务器程序使用此函数。调用格式如下:

int s, backlog;

int listen (s, backlog);

s: socket句柄,socket函数返回的socket描述符。

backlog: 定义最大队列长度,一般可定义为5。如果一个客户服务请求到来时,输入队列已满,此socket将拒绝连接请求客户程序将受到一个出错信息。

返回值: 调用成功返回0,不成功返回-1。

5。accept调用

使服务器进程进入睡眠状态,等待客户进程的连接请求。收到连接请求后将建立一个新的socket,并将新socket和客户进程连接起来。即将请求连接的客户进程的地址配置到新的socket中去,而初始socket仍具有任意网络地址,因此它可继续接收进来的服务请求。以后发送和接收数据都使用这个新建的socket。面向连接的服务器进程使用此函数。调用格式如下:

int s, addrlen;

struct sockaddr *addr;

int accept (s, addr, addrlen);

s: socket句柄,socket函数返回的socket描述符。在此socket的基础上建立一个新socket 。

addr: 用于存放客户程序socket地址。

addrlen: 客户程序socket地址长度。

返回值: 调用成功返回新建socket的描述符,否则返回-1。

6。write,writev,send,sendto,sendmsg调用

Socket API提供这五个函数来发送数据。在SCO UNIX环境中支持其中三个:面向连接的协议使用write,send两个函数。在面向连接的协议中,程序使用connect函数配置一个面向连接的socket,此socket包含远地主机的地址信息,因此,在传送数据时不需再指明目的地址。无连接的协议使用sendto,函数,在函数调用中需指明目的地址。调用格式如下:

int s, buflen, flags, namelen;

char buf [n];

struct sockaddr *name;

int write (s, buf, buflen);

int send (s, buf, buflen, flags);

int sendto (s, buf, buflen, flags, name, namelen);

s: socket句柄,accept函数返回的socket描述符。

buf: 指向一个包含传输信息的数据缓冲区。

buflen: 指明传送数据缓冲区的大小。

flags: 传输控制标志,可将数据设置为优先级较高的带外数据传送

name: 远地socket地址。

namelen: 远地socket地址长度。

返回值: 调用成功返回发送数据的长度(以字节为单位),否则返回-1。

7.read,readv,reav,recvfrom,recvmsg调用 socket API提供五个与传送数据函数对应的接收函数:read,readv,reav,recvfrom和recvmsg。SCO UNIX环境中支持其中两个:面向连接的协议使用read函数,它与write函数对应。无连接的协议使用recvfrom,它与sendto函数相对应,需在参数中指明地址。调用格式如下:

int s, buflen;

char buf [n];

int read (s, buf, buflen);

int recvfrom (s, buf, buflen, flags, name, namelen);

s: socket句柄,accept函数返回的socket描述符。

buf: 指向一个包含传输信息的数据缓冲区。

buflen: 指明传送数据缓冲区的大小。

flags: 传输控制标志,可将数据设置为优先级较高的带外数据传送。

name: 远地socket地址。

namelen: 远地socket地址长度。

返回值: 调用成功返回接收数据的长度(以字节为单位),否则返回 -1。

二.示例程序

示例程序可在SCO UNIX环境下编译,运行,分为服务器程序和客户程序,均采用面向连接的协议。可在网络或单机上运行(将程序中定义的IP地址根据情况修改)。与/usr/lib/libsocket.a一起编译。运行时先启动server进程,再启动client进程,按提示输入需传送的字符,即可看到传送结果。

服务器程序:

#include <fcntl.h>;

#include <netinet/in.h>;

#include <arpa/inet.h>;

#include <sys/types.h>;

#include <sys/socket.h>;

#define SERV_TCP_PORT 6000 //定义服务器的PORT端口

int sockfd,newsockfd;

err_dump(char *string)

{

printf("%s\n",string);

perror("system error message:";

close(sockfd);

close(newsockfd);

}

main()

{

int client,n;

char packet[80],*HELLO="hello",*cli_addr_str;

ushort cli_port;

struct sockaddr_in serv_addr,cli_addr;

if ((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)

printf("socket error.\n"; //建立socket

bzero((char *)&amp;serv_addr,sizeof(serv_addr));

serv_addr.sin_family = AF_INET;

serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

serv_addr.sin_port = htons(SERV_TCP_PORT);

//配置地址结构serv_addr

if(bind(sockfd,(struct sockaddr*)&amp;serv_addr,sizeof(serv_addr))<0)

//指明socket的数据传送端口地址

{err_dump("Server:bind error.";exit(1);}

listen(sockfd,5); //建立数据输入队列

for (;

{

strcpy(packet,"\0";

client=sizeof(cli_addr);

newsockfd=accept(sockfd,(struct sockaddr *)&amp;cli_addr,&amp;client);

//等待客户进程的连接请求

if (newsockfd<0)

{err_dump("Server:accept error.";exit(1);}

n=read(newsockfd,packet,80); //读入客户进程传送的数据

packet[n]='\0';

cli_addr_str=inet_ntoa(cli_addr.sin_addr.s_addr);

cli_port=ntohs(cli_addr.sin_port); //转换地址格式,用于显示

printf("packet from remote ip address:%s.\nremote port:%d.\n",\

cli_addr_str,cli_port);

printf("packet length:%d bytes.\n",n);

printf("packet=%s.\n",packet);

write(newsockfd,HELLO,6); //发送回应信息

close(newsockfd);

}

}

客户程序:

#include <fcntl.h>;

#include <netinet/in.h>;

#include <sys/types.h>;

#include <sys/socket.h>;

#define HOST_ADDR "134.162.33.50"

#define HOST_PORT 6000

int sockfd;

err_dump(char *string)

{

printf("%s\n",string);

perror("system error message:";

close(sockfd);

}

main()

{

char packet[80],bpacket[80],recepack[6],quit[]={'q','\0'};

struct sockaddr_in serv_addr;

int sockfd,connectfd,bindfd,writefd,n;

bzero((char *)&amp;serv_addr,sizeof(serv_addr));

serv_addr.sin_family = PF_INET;

serv_addr.sin_addr.s_addr = inet_addr(HOST_ADDR);

serv_addr.sin_port = htons(HOST_PORT);

for(;

{

printf("input string to send or 'q' to quit.\n";

gets(packet);

if (strcmp(packet,quit)==0)

exit(0);

if ((sockfd = socket(PF_INET,SOCK_STREAM,0))<0) //建立socket

{err_dump("socket error.";exit(1);}

if ((connectfd = connect(sockfd,(struct sockaddr *)&amp;serv_addr,\

sizeof(serv_addr)))<0) //连接服务器进程

{err_dump("connect error.");exit(1);}

if ((writefd=write(sockfd,packet,strlen(packet)))<0)//发送信息

{err_dump("write error.");exit(1);}

printf ("sockfd=%d,bindfd=%d,connectfd=%d,writefd=%d.\n",\

sockfd,bindfd,connectfd,writefd);

strcpy (recepack,'\0');

read(sockfd,recepack,80); //读回应信息

n = strlen(recepack);

printf("read len=%d.\n",n);

printf("packet from server:%s.\n",recepack);

close(sockfd);

}

}
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP