最近工作需要,研究了下rtsp协议的传输方式,当然了现在只是入门,以后会陆续添加工作中的所学。
rtsp是通过socket通信从而与rtsp流服务器就行数据交互的,详细的下一次在记录。借这次机会顺便研究了下unix网络编程,特此在这记录自己的一个小小的网络编程例子......
1 . server.c
- #include <stdio.h>
-
#include <sys/types.h>
-
#include <sys/socket.h>
-
#include <netinet/in.h>
-
#include <strings.h>
-
#include <stdlib.h>
-
#include <arpa/inet.h>
-
int main(int argc,char **argv)
-
{
-
struct sockaddr_in sevAddr;
-
struct sockaddr_in cliAddr;
-
struct sockaddr_in copyAddr;
- //以上三个sockaddr_in结构体代表的IPV4协议簇,
-
bzero(&sevAddr,sizeof(sevAddr));
- //bzero是专门设计的一个对给定结构体中的元素置0的接口,类似于初始化
-
sevAddr.sin_family = AF_INET; //AF_INET代表的是传输协议是tcp,udp,etc
-
sevAddr.sin_addr.s_addr = inet_addr("192.168.0.114");//inet_addr函数是将字符串转换成网络字节序的ip地址格式
- //对于IP地址的设定还可以不用固定的ip绑定,而让操作系统自己去找,这部分以后在说
-
sevAddr.sin_port = htons(36988);
- //以上三个是对server机器的地址端口号设定
- //这里注意到了htons()这个函数,作用是把本地字节序的数据转成网络字节序
- //htons,htonl,ntohs,ntohl这几个函数,前两个是本地转网络,后两个是网络转本地
- //s和l分别代表了short和long,所以可以注意到端口号用的是s,ip地址用的是l
-
int sev_fd,cli_fd;
-
int resault;
-
pid_t childPid;
-
socklen_t cliAddrSize = sizeof(cliAddr);
-
sev_fd = socket(AF_INET,SOCK_STREAM,0); //创建套接字,这里注意到AF_INET和SOCK_STREAM搭配,这表示用的是IPV4的传输协议
-
if(-1 == sev_fd)
-
{
-
printf("socket set up fail,please check it\n");
-
return 0;
-
}
-
resault = bind(sev_fd,(const struct sockaddr*)(&sevAddr),sizeof(sevAddr)); //绑定套接字到本机地址
-
if(-1 == resault)
-
{
-
printf("bind socket error ,please check it\n");
-
return 0;
-
}
-
socklen_t copyAddrSize = sizeof(copyAddr);
-
resault = getsockname(sev_fd,(struct sockaddr*)(©Addr),©AddrSize);//getsockname可以获取绑定在套接字上的地址信息
-
if(-1 == resault)
-
{
-
printf("get sockaddr info error\n");
-
}
-
printf("port is %u\n",ntohs(copyAddr.sin_port));
-
printf("ip is %u\n",ntohl(copyAddr.sin_addr.s_addr));
-
resault = listen(sev_fd,3); //监听改服务器套接字,看有否有客户端链接上来
-
if(-1 == resault)
-
{
-
printf("listen the socket fail,please check it\n");
-
return 0;
-
}
-
-
while(1)
-
{
-
cli_fd = accept(sev_fd,(struct sockaddr*)(&cliAddr),&(cliAddrSize)); //接受客户端的请求,这个接口可以顺便获得client的套接字,地址信息,端口号信息等等
-
if(-1 == cli_fd)
-
{
-
printf("accept client connect error,please check it\n");
-
}
-
if((childPid = fork()) == 0) //构建子进程为了实现并发服务器的作用
-
{
-
close(sev_fd); //关闭监听套接字
-
printf("client ip is %u\n",ntohl(cliAddr.sin_addr.s_addr));
-
printf("client port is %u\n",ntohs(cliAddr.sin_port));
-
int i =0;
-
for(;i<10;i++)
-
{
-
printf(".\n");
-
sleep(1);
-
}
-
exit(0);
-
}
-
close(cli_fd); //关闭客户端套接字
-
}
-
}
简单了来说,server的流程其实就是:套接字创建->绑定套接字到指定地址->接听套接字->接受客户端的请求
详细的专业术语这里就不多说了,关键的部分在代码中都做了注释.
2. client
- #include <stdio.h>
-
#include <sys/types.h>
-
#include <sys/socket.h>
-
#include <netinet/in.h>
-
#include <strings.h>
-
#include <stdlib.h>
-
#include <arpa/inet.h>
-
-
int main(int argc ,char **argv)
-
{
-
if(argc < 2)
-
{
-
printf("the argv is not enough\n");
-
return 0;
-
}
-
int cli_fd;
-
struct sockaddr_in sevaddr;
-
sevaddr.sin_family = AF_INET;
-
sevaddr.sin_port = htons(36988);
-
sevaddr.sin_addr.s_addr = inet_addr(argv[1]);
- //以上设置server地址信息
-
cli_fd = socket(AF_INET,SOCK_STREAM,0);
-
if(-1 == cli_fd)
-
{
-
printf("client socket set up fail,please check it\n");
-
return 0;
-
}
-
int resault;
-
resault = connect(cli_fd,(struct sockaddr*)(&sevaddr),sizeof(sevaddr)); //链接服务器
-
if(-1 == resault)
-
{
-
printf("connect the server fail,please check it\n");
-
return 0;
-
}
-
return 0;
-
}
client就相对简单了:建立套接字->链接服务器
接下来说一说INADDR_ANY这个参数的作用,在设定主机服务器ip地址的时候,不同过绑定指定ip的话可以用这个方法来绑定,这个参数的意思就是说任何服务器所带的ip地址接受到的数据都由这个服务器程序来接管。为什么这么说呢?因为很多时候可能服务器有不止一个网卡,那这么一来服务器就有多个IP,所以只要是发到这个服务器上的ip的数据,程序就都能截获了!
今天研究了下网络编程中的IO口复用技术,特此总结下:
先上代码:
1. server:
- #include <stdio.h>
-
#include <sys/types.h>
-
#include <sys/socket.h>
-
#include <netinet/in.h>
-
#include <strings.h>
-
#include <stdlib.h>
-
#include <arpa/inet.h>
-
#include <sys/select.h>
-
#include <string.h>
-
int main(int argc,char **argv)
-
{
-
struct sockaddr_in sevAddr;
-
struct sockaddr_in cliAddr;
-
struct sockaddr_in copyAddr;
-
bzero(&sevAddr,sizeof(sevAddr));
-
sevAddr.sin_family = AF_INET;
-
//sevAddr.sin_addr.s_addr = inet_addr("192.168.0.114");
-
sevAddr.sin_addr.s_addr = htonl(INADDR_ANY);
-
sevAddr.sin_port = htons(36988);
-
int sev_fd,cli_fd;
-
int resault;
-
pid_t childPid;
-
socklen_t cliAddrSize = sizeof(cliAddr);
-
sev_fd = socket(AF_INET,SOCK_STREAM,0);
-
if(-1 == sev_fd)
-
{
-
printf("socket set up fail,please check it\n");
-
return 0;
-
}
-
resault = bind(sev_fd,(const struct sockaddr*)(&sevAddr),sizeof(sevAddr));
-
if(-1 == resault)
-
{
-
printf("bind socket error ,please check it\n");
-
return 0;
-
}
-
socklen_t copyAddrSize = sizeof(copyAddr);
-
resault = getsockname(sev_fd,(struct sockaddr*)(©Addr),©AddrSize);
-
if(-1 == resault)
-
{
-
printf("get sockaddr info error\n");
-
}
-
printf("port is %u\n",ntohs(copyAddr.sin_port));
-
printf("ip is %u\n",ntohl(copyAddr.sin_addr.s_addr));
-
resault = listen(sev_fd,3);
-
if(-1 == resault)
-
{
-
printf("listen the socket fail,please check it\n");
-
return 0;
-
}
-
-
//设置IO复用的select参数属性
-
fd_set readSet;
-
struct timeval waitTime;
-
waitTime.tv_sec = 2;
-
waitTime.tv_usec = 0;
-
int client[FD_SETSIZE];
-
int i;
-
char recvbuf[100];
-
int maxi = -1; //记录在client[]中的客户端描述符数
-
for(i = 0;i<FD_SETSIZE;i++)
-
{
-
client[i] = -1;
-
}
-
FD_SET(sev_fd,&readSet);
-
int maxfd = sev_fd; //监听的描述符的最大数
-
printf("the first maxfd is %d\n",sev_fd);
-
////////////////////////////////////////
-
while(1)
-
{
-
waitTime.tv_sec = 2;
-
waitTime.tv_usec = 0;
-
FD_SET(sev_fd,&readSet);
-
maxfd = sev_fd;
-
for(i=0;i<FD_SETSIZE;i++)
-
{
-
if(client[i]!= -1)
-
{
-
FD_SET(client[i],&readSet);
-
maxi = (i+1);
-
if(client[i] > maxfd)
-
{
-
maxfd = client[i];
-
}
-
}
-
}
-
-
switch(select(maxfd+1,&readSet,NULL,NULL,&waitTime))
-
{
-
case -1:
-
{
-
printf("set select error,please check it\n");
-
return 0;
-
}break;
-
case 0:
-
{
-
printf("no client start to read\n");
-
}break;
-
default:
-
{
-
if(FD_ISSET(sev_fd,&readSet))
-
{
-
//有新的客户端需要连接
-
cli_fd = accept(sev_fd,(struct sockaddr*)(&cliAddr),&(cliAddrSize));
-
if(-1 == cli_fd)
-
{
-
printf("accept client connect error,please check it\n");
-
return 0;
-
}
-
printf("cli_fd is %d\n",cli_fd);
-
for( i = 0;i<FD_SETSIZE;i++)
-
{
-
if(client[i] == -1)
-
{
-
client[i] = cli_fd;
-
maxi = (i+1);
-
if(client[i] > maxfd)
-
{
-
maxfd = client[i];
-
}
-
break;
-
}
-
}
-
FD_SET(cli_fd,&readSet);
-
}
-
for(i=0;i<maxi;i++)
-
{
-
if(client[i] < -1)
-
{
-
//printf("no client is perpaer for the readn\n");
-
continue;
-
}
-
if(FD_ISSET(client[i],&readSet))
-
{
-
memset(recvbuf,0,sizeof(recvbuf));
-
printf("I have a client : %d\n",client[i]);
-
recvfrom(client[i],recvbuf,sizeof(recvbuf),0,NULL,NULL);
-
printf("recv the message from client is %s\n",recvbuf);
-
close(client[i]);
-
FD_CLR(client[i],&readSet);
-
client[i]=-1;
-
//对客户端描述符的读操作
-
}
-
-
}
-
}
-
/*
-
resault = select(maxfd+1,&readSet,NULL,NULL,&waitTime);
-
if(-1 == resault)
-
{
-
printf("set select error,please check it\n");
-
return 0;
-
}
-
if( 0 == resault)
-
{
-
//printf("no client has start read\n");
-
continue;
-
}
-
printf("select resault is %d.................\n",resault);
-
if(FD_ISSET(sev_fd,&readSet))
-
{
-
//有新的客户端需要连接
-
cli_fd = accept(sev_fd,(struct sockaddr*)(&cliAddr),&(cliAddrSize));
-
if(-1 == cli_fd)
-
{
-
printf("accept client connect error,please check it\n");
-
return 0;
-
}
-
printf("cli_fd is %d\n",cli_fd);
-
for( i = 0;i<FD_SETSIZE;i++)
-
{
-
if(client[i] == -1)
-
{
-
client[i] = cli_fd;
-
maxi = (i+1);
-
if(client[i] > maxfd)
-
{
-
maxfd = client[i];
-
}
-
break;
-
}
-
}
-
FD_SET(cli_fd,&readSet);
-
}
-
for(i=0;i<maxi;i++)
-
{
-
if(client[i] < -1)
-
{
-
//printf("no client is perpaer for the readn\n");
-
continue;
-
}
-
if(FD_ISSET(client[i],&readSet))
-
{
-
memset(recvbuf,0,sizeof(recvbuf));
-
printf("I have a client : %d\n",client[i]);
-
recvfrom(client[i],recvbuf,sizeof(recvbuf),0,NULL,NULL);
-
printf("recv the message from client is %s\n",recvbuf);
-
close(client[i]);
-
FD_CLR(client[i],&readSet);
-
client[i]=-1;
-
//对客户端描述符的读操作
-
}
-
}
-
*/
-
}
-
}
-
}
阅读(3712) | 评论(0) | 转发(0) |