TCP套接字编程—网络编程综合性实验介绍(共8页).doc
精选优质文档-倾情为你奉上河南师范大学综合性、设计性实验项目简介学院名称(公章):软件学院2012-2013学年第 一 学期 填表日期:2012年 9 月 18 日实验课程名称网络编程实验项目名称TCP套接字编程实验项目性质1、综合性 2、设计性主讲教师刘尚旺开课年级2010开课专业网络工程技术实验地点过街楼实验室开课日期2012年9月10日至2013年1月16日开课时间10月18日上午8:00-9:40、下午16:4018:2010月25日下午16:4018:2011月1日下午16:4018:20实验项目简介: 该实验的主要目的要求是:1.掌握服务器端程序设计的步骤: (1)使用socket()函数创建套接字; (2)将创建的套接字绑定到指定的地址结构; (3)listen()函数设置套接字为侦听模式,使服务器处于打开状态; (4)接受客户端的连接请求,建立连接; (5)接收、应答客户端的数据请求; (6)终止连接。2.掌握客户端程序设计的步骤: (1)使用socket()函数创建套接字; (2)调用connect()函数建立一个与TCP服务器的连接; (3)发送数据请求,接收服务器的数据应答; (4)终止连接。3.实现TCP套接字编程的基本函数。4.了解服务器的3种异常情况。本实验综合运用socket()等TCP套接字编程的基本函数,服务器端程序设计的步骤、客户端程序设计的步骤、socket()等TCP套接字编程的基本函数和服务器的3种异常情况等均会在本实验中有所体现,因此本实验具有一定的综合性。本实验基于Linux平台下的C语言编程实现,主要培养学生综合运用所学知识和实验方法、实验技能,提高分析、解决实际问题的能力。一、 实验目的l 运用socket()等TCP套接字编程的基本函数,设计客户端和服务器端,了解单用用户与服务器的连接和数据处理。二、 实验要求l 认真阅读和掌握本实验的相关知识。l 上机编写并运行本程序。l 保存和打印程序的运行结果,并结合程序进行分析。三、 实验内容1. 服务器端程序设计的步骤: (1)使用socket()函数创建套接字; (2)将创建的套接字绑定到指定的地址结构; (3)listen()函数设置套接字为侦听模式,使服务器处于打开状态; (4)接受客户端的连接请求,建立连接; (5)接收客户端的数据请求;并显示客户端的IP地址和端口号。(6)接受客户端传来的字符串,并进行大小写转换,然后传给客户。 (6)终止连接。2客户端程序设计的步骤: (1)使用socket()函数创建套接字; (2)调用connect()函数建立一个与TCP服务器的连接;(3)循环从命令行读入一行字符串,并传递给服务器,由服务器对字符串进行大小写转换,并将结果返回给客户程序。 (4)客户端程序显示转换后的字符串。 (4)终止连接。客户端程序如下:#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<string.h>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<netdb.h>#define PORT 1546#define MAXDATASIZE 1024void process(FILE *fp,int sockfd);/声明函数process;char *getMessage(char *sendline,int len,FILE *fp);/主函数int main(int argc,char *argv) int sockfd;/定义文件描述符; struct hostent *he; struct sockaddr_in server; if(argc!=2) printf("USAGE:%s <IP Address>n",argv0); exit(1); if(he=gethostbyname(argv1)=NULL) perror("gethostbyname() error.n"); exit(1); /*在利用套接字进行网络通信时,进程要做的第一件事就是调用socket(),产生一个套接字,并指明要使用的通信协议。函数原型 int socket(int family,int type int protocol);scoket()返回一文件描述符,该文件描述符是指通信信道的末端。如果调用失败,就返回1。参数AF_INET:TCP/IP协议集合,SOCK_STREAM:提供虚电路服务的流套接字。参数0,表示使用默认协议。*/ if(sockfd=socket(AF_INET,SOCK_STREAM,0)=-1) perror("socket() error.n"); exit(1); /判断语句,调用socket函数,将返回值赋给socket; bzero(&server,sizeof(server); server.sin_family=AF_INET; server.sin_port=htons(PORT); server.sin_addr=*(struct in_addr *)he->h_addr);/在调用connect()函数前,客户应用程序应帮定套接字地址/*客户进程在用socket()产生套接字后,用connect()将该套接字与服务器套接字相连接。*/ if(connect(sockfd,(struct sockaddr *)&server,sizeof(server)=-1) perror("connect() error.n"); exit(1); process(stdin,sockfd);/调用process()函数; close(sockfd);/关闭套接字; return 0;void process(FILE *fp,int sockfd) char sendlineMAXDATASIZE+1;/ 定义客户端的发送字符串 char recvlineMAXDATASIZE+1;/定义客户端的接送字符串 int num;/定义字符串长度 printf("connected to server.n"); printf("Input client's name:"); if(fgets(sendline,MAXDATASIZE,fp)=NULL) printf("nExit.n"); return; send(sockfd,sendline,strlen(sendline),0);/*send()与sendto()均可用来通过信道发送数据。send()可用于流式或数据报通信信道。在采用数据报传送方式时,应利用connect()函数给出所连接的套接字。send()函数形式为int send(int fd,char *buf,int len,int flags);其中,参数定义为:fd:套接字的文件描述符。buf:数据缓冲区。len:数据缓冲区字节数。flags:取值为0时,send()的功能与write()相同*/ while(getMessage(sendline,MAXDATASIZE,fp)!=NULL) send(sockfd,sendline,strlen(sendline),0);/发送字符串;/参数sockfd为套接字的文件描述符,客户端的发送字符串缓冲区,字符串的长度; if(num=recv(sockfd,recvline,MAXDATASIZE,0)=0) printf("Server terminated.n"); return; /if判断语句,如果没有接受到字符串,则连接中断; recvlinenum='0'/将接受到的字符串存在客户端的接送字符串缓冲区中; printf("server Message:%s",recvline);/输出接受到的字符; printf("nExit.n");char * getMessage(char *sendline,int len,FILE *fp) printf("Input string to server:"); return (fgets(sendline,len,fp);服务器端程序如下:#include<stdio.h>#include<stdlib.h> #include<unistd.h>#include<string.h>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#define PORT 1546#define BACKLOG 5#define MAXDATASIZE 1024void caesar(char *str);void process_client(int connfd,struct sockaddr_in client);int main() int listenfd,connfd; pid_t pid; struct sockaddr_in server,client; socklen_t len; if(listenfd=socket(AF_INET,SOCK_STREAM,0)=-1) perror("Create socked faild.n"); exit(1); int opt=SO_REUSEADDR; setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt); bzero(&server,sizeof(server); server.sin_family=AF_INET; server.sin_addr.s_addr =htonl(INADDR_ANY); server.sin_port=htons(PORT); if(bind(listenfd,(struct sockaddr *)&server,sizeof(server)=-1) perror("bind() error.n"); exit(1); if(listen(listenfd,BACKLOG)=-1) perror("listen() error.n"); exit(1); len=sizeof(client); while(1) if(connfd=accept(listenfd,(struct sockaddr *)&client,&len)=-1) perror("accept() error.n"); exit(1); if(pid=fork()>0) close(connfd); continue; else if(pid=0) close(listenfd); process_client(connfd,client); else perror("fork() error.n"); exit(1); close(listenfd); return 0;void caesar(char *str) while(*str)if(*str>='a' && *str<='z') ) *str-=32; else if(*str>='A' && *str<='Z') *str+=32; str+; void process_client(int connfd,struct sockaddr_in client) int num; char recvbufMAXDATASIZE+1; char sendbufMAXDATASIZE+1; char client_nameMAXDATASIZE+1; printf("You got a connection from %s.",inet_ntoa(client.sin_addr); num=recv(connfd,client_name,MAXDATASIZE,0); if(num=0) close(connfd); perror("client disconnected.n"); return; client_namenum-1='0' printf("Client's name is %s.n",client_name); while(num=recv(connfd,recvbuf,MAXDATASIZE,0)>0) recvbufnum='0' printf("Received client (%s) message:%s",client_name,recvbuf); bcopy(recvbuf,sendbuf,num+1);/将接受到的内容复制到要发送的字符串中 caesar(sendbuf);/调用caesar函数,将接受来的字符串大小写转换,然后在发送的客户端。 send(connfd,sendbuf,strlen(sendbuf),0);运行结果:开打终端,进入根目录用gcc o a multi_process_server.c编译服务器端程序,然后运行编译后的文件,使服务器处于打开状态。打开第二个终端,进入根目录用gcc o b client.c编译客户端程序,然后运行编译后的文件,并给出本机地址,进行连接 ,根据提示输入客户端的name及要发送的信息,然后服务器端返回转换后的信息。四、 分析总结面向连接的客户机/服务器程序工作模式,服务器进程首先用socket()建立流套接字,在用bind()套接字与本地地址绑定,在用listen()侦听,即准备好接受连接,在用accept()接收连接,然后等待客户进程连接请求的到来,在用recv()接收数据,send()发送数据,最后用close()关闭套接字;客户端进程,首先用socket()建立套接字,在用connect()将套接字与远程主机连接,在用send()发送数据,recv()接收数据,最后用close()关闭套接字。注:开课时间填本实验项目所有实验班的具体上课时间,如11月12日下午3:005:00。专心-专注-专业