基于UDP c/s通信模型
- 客户端(socket;sendto ...)
- 服务器端 ---把自己的地址公布出去 (socket;bind //绑定; recvfrom ...)
1.recvfrom函数:
ssize_t recvfrom( int sockfd, //socket的fd
void *buf, //保存数据的一块空间的地址
size_t len, //这块空间的大小
int flags, // 0 默认的接收方式 --- 阻塞方式
struct sockaddr *src_addr, //用来保存发送方的地址信息
socklen_t *addrlen //表示发送方实际的地址信息大小 );
返回值:成功:返回接收到的字节数; 失败:-1。
struct sockaddr_in srcaddr;
socklen_t addrlen = sizeof(srcaddr);
char buf[1024];
while(1)
{
recvfrom(fd,buf,sizeof(buf),0,(struct sockaddr *)&srcaddr,&addrlen);
printf("IP = %s\n",inet_ntoa(srcaddr.sin_addr));
printf("post = %d\n",ntohs(srcaddr.sin_port));
printf("buf = %s\n",buf);
}
2.bind函数:
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
(1)功能:如果该函数在服务器端调用,则表示将参数1相关的文件描述符文件与参数2 指定的接口地址关联,用于从该接口接受数据。如果该函数在客户端调用,则表示要将数据从参数1所在的描述符中取出并从参数2所在的接口设备上发送出去。
注意:如果是客户端,则该函数可以省略,由默认接口发送数据。
(2)参数:sockfd之前通过socket函数创建的文件描述符,套接字id; my_addr 是物理接口的结构体指针。表示该接口的信息。
struct sockaddr 通用地址结构 --- ip + 端口
{
u_short sa_family; 地址族
char sa_data[14]; 地址信息
};
转换成网络地址结构如下:
struct sockaddr_in ///网络地址结构
{
u_short sin_family; //地址族
u_short sin_port; //地址端口
struct in_addr sin_addr; //地址IP //"192.168.1.123"
char sin_zero[8]; //占位
};
in_addr_t === unsigned int
struct in_addr
{
in_addr_t s_addr;
}
练习:
任务1 从键盘获得数据发给服务器 --fgets
任务2 从服务器不断获取数据打印 --recvfrom
1.客户端:
int c_fd = 0;
void child_handler(int signo)
{
close(c_fd);
printf("child--exit--\n");
exit(0);
}
void father_handler(int signo)
{
close(c_fd);
printf("father--exit--\n");
exit(0);
}
int main(int argc, const char *argv[])
{
//1.socket 创建通信的一端
int fd = socket(AF_INET,SOCK_DGRAM,0);
if (fd < 0)
{
perror("socket fail");
return -1;
}
printf("fd = %d\n",fd);
struct sockaddr_in seraddr;
seraddr.sin_family = AF_INET;
seraddr.sin_port = htons(50000);
seraddr.sin_addr.s_addr = inet_addr("192.168.1.135");
char buf[1024] = {0};
//区分任务
pid_t pid = fork();
if (pid < 0)
{
perror("fork fail");
return -1;
}
if (pid > 0)
{
signal(SIGCHLD,father_handler);
c_fd = fd;
while (1)
{
printf(">");
fgets(buf,sizeof(buf),stdin);
int ret = sendto(fd,buf,strlen(buf)+1,0,(const struct sockaddr *)&seraddr,sizeof(seraddr));
printf("ret = %d\n",ret);
if (strncmp(buf,"quit",4) == 0)
{
kill(pid,SIGUSR1);
wait(NULL);
close(fd);
exit(0);
}
}
}else if (pid == 0)
{
c_fd = fd;
signal(SIGUSR1,child_handler);
while (1)
{
recvfrom(fd,buf,sizeof(buf),0,NULL,NULL);
printf("buf = %s\n",buf);
if (strncmp(buf,"quit",4) == 0)
{
close(fd);
exit(0);
}
}
}
//close(fd);
return 0;
}
2.服务器端:
int c_fd = 0;
void child_handler(int signo)
{
close(c_fd);
printf("child--exit--\n");
exit(0);
}
void father_handler(int signo)
{
close(c_fd);
printf("father--exit--\n");
exit(0);
}
int main(int argc, const char *argv[])
{
//1.socket 创建通信的一端
int fd = socket(AF_INET,SOCK_DGRAM,0);
if (fd < 0)
{
perror("socket fail");
return -1;
}
struct sockaddr_in seraddr;
seraddr.sin_family = AF_INET;
seraddr.sin_port = htons(50000);
seraddr.sin_addr.s_addr = inet_addr("192.168.1.135");
//2.bind
if (bind(fd,(struct sockaddr *)&seraddr,sizeof(seraddr)) < 0)
{
perror("bind fail");
return -1;
}
struct sockaddr_in srcaddr;
socklen_t addrlen = sizeof(srcaddr);
char buf[1024];
//3.接收数据
recvfrom(fd,buf,sizeof(buf),0,(struct sockaddr*)&srcaddr,&addrlen);
printf("--------------------\n");
printf("IP = %s\n",inet_ntoa(srcaddr.sin_addr));
printf("post = %d\n",ntohs(srcaddr.sin_port));
printf("buf = %s\n",buf);
printf("--------------------\n");
pid_t pid = fork();
if (pid < 0)
{
perror("fork fail");
return -1;
}
if (pid > 0)
{
signal(SIGCHLD,father_handler);
c_fd = fd;
while (1)
{
//3.接收数据
recvfrom(fd,buf,sizeof(buf),0,(struct sockaddr*)&srcaddr,&addrlen);
printf("--------------------\n");
printf("IP = %s\n",inet_ntoa(srcaddr.sin_addr));
printf("post = %d\n",ntohs(srcaddr.sin_port));
printf("buf = %s\n",buf);
printf("--------------------\n");
if (strncmp(buf,"quit",4) == 0)
{
kill(pid,SIGUSR1);
wait(NULL);
close(fd);
exit(0);
}
}
}else if (pid == 0)
{
signal(SIGUSR1,child_handler);
while (1)
{
printf(">");
fgets(buf,sizeof(buf),stdin);
sendto(fd,buf,strlen(buf) + 1, 0, (const struct sockaddr*)&srcaddr,sizeof(srcaddr));
if (strncmp(buf,"quit",4) == 0)
{
close(fd);
exit(0);
}
}
}
return 0;
}
基于TCP c/s通信模型
tcp 客户端:
(1)建立连接:
- socket //买了一部手机;
- bind //可选 //插上sim卡;
- connect //拨打电话 ....
(2)通信过程:(read;write;close)
connect函数:
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
(1)功能:该函数固定有客户端使用,表示从当前主机向目标主机发起链接请求。
(2)参数:sockfd:本地socket创建的套接子id;addr:程目标主机的地址信息;
addrlen: 参数2的长度。
(3)返回值:成功 0;失败 -1;
int main(int argc, const char *argv[])
{
int fd = socket(AF_INET,SOCK_STREAM,0);
if (fd < 0)
handle_error("socket fail");
struct sockaddr_in seraddr;
seraddr.sin_family = AF_INET;
seraddr.sin_port = htons(50000);
seraddr.sin_addr.s_addr = inet_addr("192.168.1.135");
if (connect(fd,(const struct sockaddr*)&seraddr,sizeof(seraddr)) < 0)
handle_error("connect fail");
return 0;
}
tcp服务器:
(1)建立连接
- socket //买了一部手机
- bind //插上sim卡
- listen //监听 客户端的连接请求
- accept //接听 ---这一步完成之后 连接就建立好了,之后就可以收发数据
(2)通信过程 (read;write;close)
listen函数:
int listen(int sockfd, int backlog);
accept函数:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int main(int argc, const char *argv[])
{
int listen_fd = socket(AF_INET,SOCK_STREAM,0);
if (listen_fd < 0)
handle_error("socket fail");
struct sockaddr_in seraddr;
seraddr.sin_family = AF_INET;
seraddr.sin_port = htons(50000);
seraddr.sin_addr.s_addr = inet_addr("192.168.1.135");
if (bind(listen_fd,(const struct sockaddr*)&seraddr,sizeof(seraddr)) < 0)
handle_error("bind fail");
if (listen(listen_fd,5) < 0)
handle_error("listen fail");
int connfd = accept(listen_fd,NULL,NULL);
if (connfd < 0)
handle_error("accept fail");
printf("connfd = %d\n",connfd);
return 0;
}
struct sockaddr *addr //通用地址结构类型,并没有实际去用,实际用到都是具体地址结构类型
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};/* Internet address. */
struct in_addr {
uint32_t s_addr; /* address in network byte order */
};