言之者无罪,闻之者足以戒。 - “诗序”
1,TCP是什么?
TCP传输控制协议
向用户进程提供可靠的全双工字节流(字节流:给每一个字节编序)
2,UDP是什么?
UDP用户数据报协议
是一种无连接的协议
3,获取时间服务的客户端
(1),创建一个的的IPv4(AF_INET)的字节流(SOCK_STREAM)套接字
(2),连接到IP地址,端口号为8888的服务器
(3),写一个数据到服务器
(4),接收服务器传回来的数据并显示到标准输出
(5),关闭套接字
下面来看一下客户端的程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc,char *argv[])
{
int sockfd;
struct sockaddr_in servaddr;
char buf[100];//存储读取的内容
int bytes;//存储读取的字节数
if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0)//创建套接字
{
printf("socket error\n");
return -1;
}
//结构体中成员变量初始化为0
bzero(&servaddr,sizeof(servaddr));
//初始化成员变量
servaddr.sin_family = AF_INET;//IPv4
servaddr.sin_addr.s_addr = inet_addr("192.168.177.133");//转换为地址格式
servaddr.sin_port = htons(8888);//主机序转换到网络序
//连接服务器
if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) < 0)//绑定服务器ip和端口到>套结字
{
perror("connect error");
return -2;
}
//存储读取的数据和读取的字节数
bytes == read(sockfd,buf,100);
if(bytes < 0)
{
printf("Error ,read failed\n");
return -3;
}
//如果读取的字节数为0 ,就说明连接已经关闭了
if(0 == bytes)
{
printf("Server close connection\n");
return -4;
}
//打印读取的字节数和读取的内容
printf("read bytes %d\n",bytes);
printf("Time: %s\n",buf);
//关闭套结字
close(sockfd);
return 0;
}
上面的程序的设计思路已经说了,我也在程序中写了必要的注释,相信是比较容易接受。
如图4所示,提供时间的服务器端:
(1),绑定已知的IPv4的的的的地址(INADDR_ANY)和端口号(8888)
(2),将套接字转换成监听套接字
(3),睡眠等待客户端连接
(4),读取客户端数据
(5),将收到的数据发送给客户端
(6),睡眠1S后关闭套接字
接下来看一下服务器的程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
#define MAX_LISTEN_QUE 5
int main(int argc,char *argv[])
{
int listenfd,sockfd,opt=1;//listenfd创建的普通套接字,sockfd通信套接字
struct sockaddr_in server,client;
char buf[200];
socklen_t len;
int timep;
int ret;
//创建套接字
listenfd = socket(AF_INET,SOCK_STREAM,0);
if(listenfd < 0)
{
perror("Create socket fail");
return -1;
//设置套结字关联的选项(设置地址的重用)
if((ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) < 0)
{
perror("Error ,set socket reuse addr failed");
return -1;
}
//清空结构体中的变量值
bzero(&server, sizeof(server));
//初始化结构体的变量
server.sin_family = AF_INET;//IPv4
server.sin_port = htons(8888);//主机转换到网络
server.sin_addr.s_addr = htonl(INADDR_ANY);//同上(使用这个宏套接字可以绑定到所有的端>口)
//获取结构体地址长度
len = sizeof(struct sockaddr);
//绑定服务器ip地址和端口到套接字
if(bind(listenfd, (struct sockaddr *)&server, len)<0)
{
perror("bind error.");
return -1;
}
//设置服务器的最大连接数
listen(listenfd, MAX_LISTEN_QUE);
//迭代(就是可以有多个客户端只是不能同时通信)
while(1)
{
//等待客户端请求,如果请求到来,返回一个新的socket
//服务器和客户端利用新的socket来通信
sockfd = accept(listenfd, (struct sockaddr *)&client, &len);
if(sockfd < 0)
{
perror("accept error.");
return -1;
}
//显示系统的当前时间
timep = time(NULL);
//将数据按照一定的格式转换之后复制到buf
//ctime返回一个表示当地时间的字符串
snprintf(buf, sizeof(buf), "%s", ctime(&timep));
//向套接字中写入buf存储的时间
write(sockfd, buf, strlen(buf));
//打印存储的字节数
printf("Bytes:%d\n", strlen(buf));
//打印套接字的文件描述符
printf("sockfd=%d\n", sockfd);
//关闭套接字
close(sockfd);
}
return 0;
}