Linux系统编程实验七网络编程资料.docx

上传人:b****6 文档编号:8948220 上传时间:2023-02-02 格式:DOCX 页数:15 大小:188.53KB
下载 相关 举报
Linux系统编程实验七网络编程资料.docx_第1页
第1页 / 共15页
Linux系统编程实验七网络编程资料.docx_第2页
第2页 / 共15页
Linux系统编程实验七网络编程资料.docx_第3页
第3页 / 共15页
Linux系统编程实验七网络编程资料.docx_第4页
第4页 / 共15页
Linux系统编程实验七网络编程资料.docx_第5页
第5页 / 共15页
点击查看更多>>
下载资源
资源描述

Linux系统编程实验七网络编程资料.docx

《Linux系统编程实验七网络编程资料.docx》由会员分享,可在线阅读,更多相关《Linux系统编程实验七网络编程资料.docx(15页珍藏版)》请在冰豆网上搜索。

Linux系统编程实验七网络编程资料.docx

Linux系统编程实验七网络编程资料

实验七:

网络编程

●实验目的:

学会Linux的socket套接字网络编程,熟悉使用TCP传输协议的网络编程流程

●实验要求:

编写使用TCP协议的服务器程序和客户端程序,客户端向服务器发送字符串,服务器打印收到的字符串

●实验器材:

软件:

安装了Linux的vmware虚拟机

硬件:

PC机一台

●实验步骤:

1、编写服务器端代码tcp_server.c

#include

#include

#include

#include

#include

#include

#include

#include

#defineportnumber3333

intmain(intargc,char*argv[])

{

intsockfd,new_fd;

structsockaddr_inserver_addr;

structsockaddr_inclient_addr;

intsin_size;

intnbytes;

charbuffer[1024];

/*1、服务器创建sockfd描述符*/

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

IPV4;SOCK_STREAM:

TCP

{

fprintf(stderr,"Socketerror:

%s\n\a",strerror(errno));

exit

(1);

}

/*2、服务器端填充sockaddr结构*/

bzero(&server_addr,sizeof(structsockaddr_in));//初始化,置0

server_addr.sin_family=AF_INET;//Internet

server_addr.sin_addr.s_addr=htonl(INADDR_ANY);//(将本机器上的long数据转化为网络上的long数据)服务器程序能运行在任何ip的主机上

//server_addr.sin_addr.s_addr=inet_addr("192.168.1.1");//用于绑定到一个固定IP,inet_addr用于把数字加格式的ip转化为整形ip

server_addr.sin_port=htons(portnumber);//(将本机器上的short数据转化为网络上的short数据)端口号

/*3、绑定地址结构体*/

if(bind(sockfd,&server_addr,sizeof(server_addr))<0)

{

printf(“binderror!

”);

exit(-1);

}

/*4、设置监听允许连接的最大客户端数*/

if(listen(sockfd,0)<0)

{

printf(“listenerror!

”);

exit(-1);

}

while

(1)

{

/*5、服务器阻塞,直到客户程序建立连接*/

sin_size=sizeof(structsockaddr_in);

if(new_fd=accept(sockfd,&server_addr,&sin_size)<0)

{

printf(“accepterror!

”);

exit(-1);

}

//连接成功后打印客户端IP

fprintf(stderr,"Servergetconnectionfrom%s\n",inet_ntoa(client_addr.sin_addr));//将网络地址转换成.字符串

//6、read()函数读取客户端发送的消息

nbytes=read(new_fd,buffer,1024);

buffer[nbytes]='\0';

printf("Serverreceived%s\n",buffer);

/*这个通讯已经结束*/

close(new_fd);

/*循环下一个*/

}

/*结束通讯*/

close(sockfd);

exit(0);

}

/********************完整程序*************************

#include

#include

#include

#include

#include

#include

#include

#include

#include//inet_ntoa()

#include//read(),close()

#defineportnumber3333

intmain(intargc,char*argv[])

{

intsockfd,new_fd;

structsockaddr_inserver_addr;

structsockaddr_inclient_addr;

intsin_size;

intnbytes;

charbuffer[1024];

/*1、服务器创建sockfd描述符*/

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

fprintf(stderr,"Socketerror:

%s\n\a",strerror(errno));

exit

(1);

}

/*2、服务器端填充sockaddr结构*/

bzero(&server_addr,sizeof(structsockaddr_in));

server_addr.sin_family=AF_INET;

server_addr.sin_addr.s_addr=htonl(INADDR_ANY);

server_addr.sin_port=htons(portnumber);

/*3、绑定地址结构体*/

if(bind(sockfd,(structsockaddr*)(&server_addr),sizeof(structsockaddr))<0)

{

printf("binderror!

");

exit(-1);

}

/*4、设置监听允许连接的最大客户端数*/

if(listen(sockfd,5)<0)

{

printf("listenerror!

");

exit(-1);

}

while

(1)

{

/*5、服务器阻塞,直到客户程序建立连接*/

sin_size=sizeof(structsockaddr_in);

if((new_fd=accept(sockfd,(structsockaddr*)(&client_addr),&sin_size))<0)

{

printf("accepterror!

");

exit(-1);

}

//连接成功后打印客户端IP

if(fork==0){//fork(),创建子进程,多个进程不需等候

fprintf(stderr,"servergetconnectionfrom%s\n",inet_ntoa(client_addr.sin_addr));

//6、read()函数读取客户端发送的消息

nbytes=read(new_fd,buffer,1024);

buffer[nbytes]='\0';

printf("Serverreceived%s\n",buffer);

/*这个通讯已经结束*/

close(new_fd);

}

elseclose(new_fd);//结束父进程

/*循环下一个*/

}

/*结束通讯*/

return0;

}

******************************/

2、编写客户端代码tcp_client.c

#include

#include

#include

#include

#include

#include

#include

#include

#defineportnumber3333

intmain(intargc,char*argv[])

{

intsockfd;

charbuffer[1024];

structsockaddr_inserver_addr;

structhostent*host;

/*1、客户程序开始建立sockfd描述符*/

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

Internet;SOCK_STREAM:

TCP

{

fprintf(stderr,"SocketError:

%s\a\n",strerror(errno));

exit

(1);

}

/*2、客户程序填充服务端的资料*/

bzero(&server_addr,sizeof(server_addr));//初始化,置0

server_addr.sin_family=AF_INET;//IPV4

server_addr.sin_port=htons(portnumber);//(将本机器上的short数据转化为网络上的short数据)端口号

server_addr.sin_addr.s_addr=htonl(INADDR_ANY);

/*3、connect函数,客户程序发起连接请求*/

if((connect(sockfd,&server_addr,sizeof(server_addr))<0)

{

printf(“conneterror!

”);

exit(-1);

}z

/*连接成功了*/

printf("Pleaseinputchar:

\n");

/*等待终端输入数据*/

fgets(buffer,1024,stdin);

//4、write函数发送buffer数据

write(sockfd,buffer,strlen(buffer));

/*结束通讯*/

close(sockfd);

exit(0);

}

/******************完整程序**************************

#include

#include

#include

#include

#include

#include

#include

#include

#include//inet_ntoa()

#include//read(),close()

#defineportnumber3333

intmain(intargc,char*argv[])

{

intsockfd;

charbuffer[1024];

structsockaddr_inserver_addr;

structhostent*host;

/*1、客户程序开始建立sockfd描述符*/

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

//AF_INET:

Internet;SOCK_STREAM:

TCP

{

fprintf(stderr,"SocketError:

%s\a\n",strerror(errno));

exit

(1);

}

/*2、客户程序填充服务端的资料*/

bzero(&server_addr,sizeof(server_addr));//初始化,置0

server_addr.sin_family=AF_INET;//IPV4

server_addr.sin_port=htons(portnumber);

//(将本机器上的short数据转化为网络上的short数据)端口号

server_addr.sin_addr.s_addr=htonl(INADDR_ANY);

/*3、connect函数,客户程序发起连接请求*/

if(connect(sockfd,(structsockaddr*)(&server_addr),sizeof(server_addr))<0){

printf("conneterror!

");

exit(-1);

}

/*连接成功了*/

printf("Pleaseinputchar:

\n");

/*等待终端输入数据*/

fgets(buffer,1024,stdin);

//4、write函数发送buffer数据

write(sockfd,buffer,strlen(buffer));

/*结束通讯*/

close(sockfd);

exit(0);

return0;

}

************************************************/

3、编译并运行应用程序

 

 

先运行服务器程序tcp_server,然后在另一个终端中运行客户端程序tcp_client。

从运行情况可以看出,在没有客户端连接上来时服务器程序阻塞在accept函数上,等待连接,当有客户端程序连接上来时,阻塞在read函数上,等待读取消息。

客户端发送一条消息后结束,服务器读取消息并打印出来,继续等待新的连接

●上机报告要求:

上面的TCP服务器每次只能处理一次客户端请求,尝试将他改写成并发TCP服务器,即可以处理多个客户端请求,测试成功后将代码写入实验报告。

/***********************************************************

#include

intscoket(intdomain,inttype,intprotocol)

socket函数对应于普通文件的打开操作。

普通文件的打开操作返回一个文件描述字,而socket()用于创建一个socket描述符(socketdescriptor),它唯一标识一个socket。

这个socket描述字跟文件描述字一样,后续的操作都有用到它,把它作为参数,通过它来进行一些读写操作。

正如可以给fopen的传入不同参数值,以打开不同的文件。

创建socket的时候,也可以指定不同的参数创建不同的socket描述符,socket函数的三个参数分别为:

domain:

即协议域,又称为协议族(family)。

常用的协议族有,

AF_INET(IPv4英特网域)、

AF_INET6(IPv6英特网域)、

AF_LOCAL(或称AF_UNIX,Unix域socket)、

AF_ROUTE等等。

协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。

type:

指定socket类型。

常用的socket类型有,

SOCK_STREAM(流式套接字TCP)、

SOCK_DGRAM(数据报套接字UDP)、

SOCK_RAW、

SOCK_PACKET、

SOCK_SEQPACKET等等(socket的类型有哪些?

)。

protocol:

故名思意,就是指定协议。

(按给定的域和套接字类型选择默认协议,通常为0)常用的协议有,

IPPROTO_TCP、

IPPTOTO_UDP、

IPPROTO_SCTP、

IPPROTO_TIPC等,

它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议

当我们调用socket创建一个socket时,返回的socket描述字它存在于协议族(addressfamily,AF_XXX)空间中,但没有一个具体的地址。

如果想要给它赋值一个地址,就必须调用bind()函数,否则就当调用connect()、listen()时系统会自动随机分配一个端口。

 

字节序转换

不同类型的CPU对变量的字节存储顺序可能不同:

有的系统是大端字节序,即高位在低地址,即低位在高地址,而有的系统如x86是小端字节序,即低位在低地址,高位在高地址,而网络传输的数据顺序是一定要统一的,所有当内部字节存储顺序和网络字节序(大端字节序)不同时,就一定要进行转换

unsignedlonghtonl(unsignedlonghostlong);

unsignedshorthtons(unsignedshorthostshort);

unsignedlongntohl(unsignedlongnetlong);

unsignedshortntohs(unsignedshortnetshort);

htonl()函数是将32位无符号长整形数据从主机字节序转换为网络字节序

返回值:

  htonl()返回一个网络字节顺序的值。

htons()函数是将16位无符号短整形数据从主机字节序转换为网络字节序

返回值:

  htons()返回一个网络字节顺序的值。

htonl()/htons()函数是将32/16位整形数据从网络字节序转换为主机字节序

通用地址格式

structsockaddr{

unsignedshortsa_family; /*地址族,AF_xxx*/

charsa_data[14]; /*14字节的协议地址*/

};

sa_family:

协议族,采用“AF_xxx”形式,如AF_INET(IP协议族)(domain)

sa_data:

1包含了一些远程电脑的地址、端口和套接字的数目,它里面的数据是夹杂在一起的

structsockaddr_in{

shortintsin_family;/*地址族*/

unsignedshortintsin_port;/*端口号*/

structin_addrsin_addr;/*Internet地址*/

unsignedcharsin_zero[8];/*与structsockaddr一样的长度*/

};

IP地址通常由数字加点(192.168.0.1)的形式表示,而structin_addr中使用的IP地址是由32位的整数表示的,为了转换我们可以使用下面两个函数:

in_addr_tinet_addr(constchar*strptr);

将一个点分十进制的IP转换成一个长整数型数(u_long类型)

char*inet_ntoa(structin_addrin)

函数里面a代表ascii,n代表network

inet_aton是将a.b.c.d形式的IP转换为32位的IP,存储在inp指针里面,

inet_ntoa是将32位IP转换为a.b.c.d的格式

 

structin_addr{

unsignedlongs_addr;

};

 

#include

intbind(intsockfd,conststructsockaddr*addr,socklen_taddrlen);

函数的三个参数分别为:

sockfd:

即socket描述字,它是通过socket()函数创建了,唯一标识一个socket。

bind()函数就是将给这个描述字绑定一个名字。

addr:

一个const struct sockaddr*指针,指向要绑定给sockfd的协议地址。

这个地址结构根据地址创建socket时的地址协议族的不同而不同。

 

addrlen:

对应的是地址的长度。

(通常设为scokaddr结构的长度)

返回值:

成功返回0,否则返回-1

 

如果作为一个服务器,在调用socket()、bind()之后就会调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。

#include

intconnect(intsockfd,conststructsockaddr*addr,socklen_taddrlen);

sockfd:

为客户端的socket描述字,

addr:

为服务器的socket地址(为指向sockaddr结构的指针),

addrlen:

为socket地址的长度。

客户端通过调用connect函数来建立与TCP服务器的连接。

返回值:

0成功,-1错误

#include

intlisten(intsockfd,intbacklog);

sockfd,:

为要监听的socket描述字,

backlog:

为相应socket可以排队的最大连接个数。

(系统默认值为20,0表示无限制)

socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。

返回值:

0成功,-1失败

 

intaccept(intsockfd,structsockaddr*addr,socklen_t*addrlen);

sockfd:

为(被监听的)服务器的socket描述字,

addr:

为指向struct sockaddr*的指针(指向sockaddr_in结构的指针,存放提出连接请求服务的主机IP和端口号信息),用于返回客户端的协议地址,

addrlen:

为协议地址的长度。

返回值:

成功,返回值是由内核自动生成的一个全新的描述字,进程可以通过这个新的描述符同客户进程传输数据。

失败返回-1。

 

#include

ssize_tread(intfd,void*b

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

当前位置:首页 > 考试认证 > 司法考试

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

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