实验9网络编程TCP.docx
《实验9网络编程TCP.docx》由会员分享,可在线阅读,更多相关《实验9网络编程TCP.docx(17页珍藏版)》请在冰点文库上搜索。
实验9网络编程TCP
实验3-1网络编程-TCP
●实验目的:
1、理解网络编程的原理
2、掌握TCPsocket的使用流程
3、掌握select多路复用技术
●实验要求:
熟练使用该节所介绍网络编程API相关函数的使用方法。
●实验器材:
软件:
1.安装了Ubunt的vmware虚拟机
硬件:
PC机一台
●实验步骤:
1、首先配置Ubunt的网络,使其与Window的IP地址在同一网段。
网络配置方法如下:
修改配置文件
sudovi/etc/network/interfaces修改如下:
autolo
ifaceloinetloopback
autoeth0
#ifaceeth0inetstatic
#address192.168.X.X//修改IP地址为WindowsIP地址+100
#gateway192.168.X.X//修改为Window的网关
#netmask255.255.255.0
重启网络管理器
sudoservicenetwork-managerrestart
重启网络服务:
sudo/etc/init.d/networkingforce-reload==>重新加载网路配置文件
sudo/etc/init.d/networkingrestart
根据所学的TCP协议,服务器端和客户端进行通信的创建流程,实现客户端发送据到服务器端,服务器端接收数据。
并将服务器端程序和客户端程序在两台电脑上进行运行演示。
服务器端的创建流程为:
各个函数的使用方法参考实验文件夹下的《嵌入式Linux网络编程.pdf》。
下面代码是设置socket可重绑定:
//SetSockopt
intsinsize=1;
intret=setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&sinsize,sizeof(int));
if(ret!
=0)
{
perror("Setsockoptfail!
\n");
exit-1;
}
server.c的参考代码如下:
#include
2、修改上题代码用线程实现客户端和服务器端可以重复收发数据,模拟聊天。
其中server.c的参考代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#definePORT6000
#defineSERVER_IP"192.168.0.101"
void*routine(void*arg)
{
intnewsockfd=*(int*)arg;
charbuf[10];
while
(1)
{
bzero(buf,10);
intsize=recv(newsockfd,buf,sizeof(buf),0);
buf[size]='\0';
printf("recivefromclientis:
%s",buf);
}
}
intmain()
{
charbuf[10]="hello";
//bzero(buf,10);
intsockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0)
{
perror("socketfail\n");
return-1;
}
//SetSockopt
intsinsize=1;
intret=setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&sinsize,sizeof(int));
if(ret!
=0)
{
perror("Setsockoptfail!
\n");
exit-1;
}
structsockaddr_ins;
memset(&s,0,sizeof(s));
s.sin_family=AF_INET;
s.sin_port=htons(6000);
s.sin_addr.s_addr=inet_addr("192.168.0.101");//要求大端模式的端口号和IP地址
intbi=bind(sockfd,(structsockaddr*)&s,sizeof(structsockaddr));
if(bi<0)
{
perror("bindfail\n");
}
listen(sockfd,5);
structsockaddr_inc;
intsize=sizeof(structsockaddr);
intnewsockfd=accept(sockfd,(structsockaddr*)&c,&size);
/**********************************创建线程********************************************/
pthread_tpid;
pthread_create(&pid,NULL,routine,(void*)&newsockfd);
while
(1)
{
memset(buf,0,10);
fgets(buf,10,stdin);
intslen=send(newsockfd,buf,strlen(buf),0);
if(slen<0)
{
printf("sendfailed\n");
return-1;
}
}
//recv(newsockfd,buf,,);//如果socket没数据就阻塞
//如果服务器不想接收数据,要退出关闭sockfd
pthread_join(pid,NULL);
close(newsockfd);
close(sockfd);
return0;
}
3、修改第2题的代码,实现多个客户端通过服务器端实现数据的转发,即客户端发送的数据通过服务器端,转发给所有的客户端。
服务器端server.c的参考代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#definePORT6000;
#defineSERVER_IP"192.168.0.101"
intfd[10]={0};
pthread_tpthread_id[10]={0};
void*routine(void*arg)
{
intnewsockfd=*(int*)arg;
charbuf[10];
inti;
while
(1)
{
bzero(buf,10);
intsize=recv(newsockfd,buf,sizeof(buf),0);
buf[size]='\0';
printf("recivefromclientis:
%s",buf);
for(i=0;i<10;i++)
{
if(fd[i]!
=0&&fd[i]!
=newsockfd)
send(fd[i],buf,sizeof(buf),0);
}
if(strcmp("ESC",buf)==0)
break;
}
pthread_exit(NULL);
}
intmain()
{
charbuf[10]="hello";
//bzero(buf,10);
intsockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0)
{
perror("socketfail\n");
return-1;
}
//SetSockopt
intsinsize=1;
intret=setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&sinsize,sizeof(int));
if(ret!
=0)
{
perror("Setsockoptfail!
\n");
exit-1;
}
structsockaddr_ins;
memset(&s,0,sizeof(s));
s.sin_family=AF_INET;
s.sin_port=htons(6000);
s.sin_addr.s_addr=inet_addr("192.168.0.101");//要求大端模式的端口号和IP地址
intbi=bind(sockfd,(structsockaddr*)&s,sizeof(structsockaddr));
if(bi<0)
{
perror("bindfail\n");
}
listen(sockfd,5);
structsockaddr_inc;
intsize=sizeof(structsockaddr);
/**********************************创建线程********************************************/
pthread_tpid;
intnewsockfd;
inti;
while
(1)
{
newsockfd=accept(sockfd,(structsockaddr*)&c,&size);
pthread_create(&pid,NULL,routine,(void*)&newsockfd);
for(i=0;i<10;i++)
{
if(fd[i]==0)
{
fd[i]=newsockfd;
break;
}
}
for(i=0;i<10;i++)
{
if(pthread_id[i]==0)
{
pthread_id[i]=pid;
break;
}
}
}
//recv(newsockfd,buf,,);//如果socket没数据就阻塞
//如果服务器不想接收数据,要退出关闭sockfd
pthread_join(pid,NULL);
close(sockfd);
return0;
}
4、修改第3题的代码,通过多路复用,select函数实现第3题的功能。
server_select.c参考代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#definePORT6000;
#defineSERVER_IP"192.168.0.101"
intmain()
{
intfds[20]={0};
intmaxfd=0;
charbuf[10];
bzero(buf,10);
inti;
intsockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0)
{
perror("socketfail\n");
return-1;
}
if(sockfd>maxfd)
maxfd=sockfd;
//SetSockopt
intsinsize=1;
intret=setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&sinsize,sizeof(int));
if(ret!
=0)
{
perror("Setsockoptfail!
\n");
exit-1;
}
structsockaddr_ins;
memset(&s,0,sizeof(s));
s.sin_family=AF_INET;
s.sin_port=htons(6000);
s.sin_addr.s_addr=inet_addr("192.168.0.101");//要求大端模式的端口号和IP地址
intbi=bind(sockfd,(structsockaddr*)&s,sizeof(structsockaddr));
if(bi<0)
{
perror("bindfail\n");
}
listen(sockfd,5);
structsockaddr_inc;
intsize=sizeof(structsockaddr);
/**********************************创建线程********************************************/
fd_setst;
intnewsockfd;
structtimevaltv;
memset(&tv,0,sizeof(tv));
tv.tv_sec=5;
tv.tv_usec=0;
while
(1)
{
tv.tv_sec=5;
tv.tv_usec=0;
FD_ZERO(&st);
FD_SET(sockfd,&st);
for(i=0;i<20;i++)
{
if(fds[i]!
=0)
FD_SET(fds[i],&st);
}
intsizes=select(maxfd+1,&st,NULL,NULL,&tv);
inti;
if(sizes==0)
continue;
if(sizes>0)
{
if(FD_ISSET(sockfd,&st))
{
newsockfd=accept(sockfd,(structsockaddr*)&c,&size);
if(newsockfd>maxfd)
maxfd=newsockfd;
for(i=0;i<20;i++)
{
if(fds[i]==0)
{
fds[i]=newsockfd;
break;
}
}
}
memset(buf,0,sizeof(buf));
intj;
for(i=0;i<20;i++)
{
if((fds[i]!
=0)&&FD_ISSET(fds[i],&st))
{
intrlen=recv(fds[i],buf,sizeof(buf),0);
if(rlen==0)
{
close(fds[i]);
fds[i]=0;
}
printf("recivefromclientis:
%s",buf);
for(j=0;j<20;j++)
{
if(fds[j]!
=0&&(j!
=i))
{
intslen=send(fds[j],buf,strlen(buf),0);
if(slen<0)
{
printf("sendfailed\n");
return-1;
}
}
}
}
}
}
}
//如果服务器不想接收数据,要退出关闭sockfd
close(newsockfd);
close(sockfd);
return0;
}
客户端client_select.c代码独立完成。