2016-2017第一学期 20155332 第八周课堂实践
1. socket套接字介绍
-
socket机制其实就是包括socket, bind, listen, connect, accept等函数的方法,其通过指定的函数实现不同的协议(IP4,IP6等)的数据在不同层之间的传输和获取等处理。其实个人理解socket就是处于应用层和TCP/IP协议之间的一个中间层,具体的数据分析,重组,拆分等操作对于应用层的网络编程者来说都是不可见的,这些都有协议栈内核实现,应用层的网络编程会通过设置socket机制中创建socket时参数不同,而接收或者发送不同类型的数据。
-
对于TCP/IP在这里就不过多的讲,但是需要提及的是经典的TCP/IP参考模型是分为4个层次:应用层,传输层,网络互联层,主机到网络层。标准的套接字编程主要是指TCP和UDP的网络编程,socket网络编程的模式就是分server和client,通过server端首先建立,client端联接进行通信。网络协议栈内核实现的功能主要就是在数据到达每一层时,给数据加上或者去掉协议包头,或者进行校验,数据重组,拆分等操作,最后得到我们想要的数据格式。
-
下面简单列一下TCP/IP参考模型中主要的协议类型
-
标准套接字分为TCP和UDP协议两种不同type的工作流程,TCP网络编程相对于UDP来说相对复杂,因为TCP是面向连接的服务,其中包括三次握手建立连接的过程,而UDP则是无连接的服务,下图介绍了TCP服务使用socket套接字建立连接的过程,以及进行数据交互的过程。
-
TCP和UDP的网络编程模式有两种,一种是服务器模式,另一种是客户端模式,因为TCP是面向连接的服务,所以在socket机制当中,TCP的服务器模式比UDP的服务器模式多了listen,accept函数,TCP客户端比UDP客户端多了connect函数。下面是TCP和UDP网络编程的两种模式流程图。下面将结合图2,3,4介绍一下TCP socket的机制是如何实现的。
-
TCP 服务器端与客户端通信流程 -
UDP服务器端和客户端通信流程
客户端代码
#include <stdio.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <time.h>
#define SPORT 8888
#define SIZE 100
int main(void)
{
int sockfd, clientfd;
struct sockaddr_in sockServer;
struct timeval tv;
fd_set readfds;
int readlen, writelen;
char buffer[SIZE];
time_t timet;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
perror("create socket failed!
");
return -1;
}
bzero(&sockServer, 0);
sockServer.sin_family = AF_INET;
sockServer.sin_port = htons(SPORT);
sockServer.sin_addr.s_addr = htonl(INADDR_ANY);
if(connect(sockfd, (struct sockaddr *)&sockServer, sizeof(struct sockaddr_in)) < 0)
{
perror("connect failed!
");
close(sockfd);
}
while(1)
{
int ret;
FD_ZERO(&readfds);
FD_SET(1, &readfds);
FD_SET(sockfd, &readfds);
tv.tv_usec = 0;
tv.tv_sec = 60;
ret = select(sockfd+1, &readfds, NULL, NULL, &tv);
switch(ret)
{
case 0:
printf("select timeout!
");
break;
case -1:
perror("select return failed!
");
goto closesocket;
default:
if(FD_ISSET(sockfd, &readfds) > 0)
{
memset(buffer, 0, SIZE);
readlen = read(sockfd, buffer, SIZE);
if(readlen < 0)
{
perror("read data failed!
");
goto closesocket;
}
time(&timet);
//printf("Opposite: %s %s", "Server", ctime(&timet));
printf("客户端IP:%s
",htonl(INADDR_ANY));
printf("服务器实现者学号:20155332
");
printf("%s:%s
", "当前时间", ctime(&timet));
strcat(buffer, "
");
writelen = write(0, buffer, readlen + 1);
if(writelen < 0)
{
perror("write data failed!
");
goto closesocket;
}
}
if(FD_ISSET(1, &readfds) > 0)
{
time(&timet);
printf("Owner: %d %s
", sockfd, ctime(&timet));
printf("客户端IP:%s
",htonl(INADDR_ANY));
printf("服务器实现者学号:20155332
");
printf("%s:%s
", "当前时间", ctime(&timet));
memset(buffer, 0, SIZE);
readlen = read(1, buffer, SIZE);
if(readlen < 0)
{
perror("read data failed!
");
goto closesocket;
}
writelen = write(sockfd, buffer, readlen);
if(writelen < 0)
{
perror("write data failed!
");
goto closesocket;
}
}
}
closesocket:
close(clientfd);
}
close(sockfd);
return 0;
}
服务器代码
#include <stdio.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <time.h>
#define SPORT 8888
#define BACKLOG 5
#define SIZE 100
int main(void)
{
int sockfd, clientfd;
struct sockaddr_in sockServer, sockClient;
struct timeval tv;
fd_set readfds, writefds;
int readlen, writelen;
char buffer[SIZE];
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
perror("create socket failed!
");
return -1;
}
bzero(&sockServer, 0);
sockServer.sin_family = AF_INET;
sockServer.sin_port = htons(SPORT);
sockServer.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sockfd, (struct sockaddr *)&sockServer, sizeof(struct sockaddr_in)) < 0)
{
perror("bind socket failed!
");
return -1;
}
if(listen(sockfd, BACKLOG) < 0)
{
perror("listen failed!
");
}
printf("Server is listening ......
");
while(1)
{
int len = sizeof(struct sockaddr_in);
int ret;
time_t timet;
clientfd = accept(sockfd, (struct sockaddr *)&sockClient, &len);
if(clientfd < 0)
{
perror("accept failed!
");
return -1;
}
for(;;)
{
FD_ZERO(&readfds);
FD_SET(1, &readfds);
FD_SET(clientfd, &readfds);
tv.tv_usec = 0;
tv.tv_sec = 60;
ret = select(clientfd+1, &readfds, NULL, NULL, &tv);
switch(ret)
{
case 0:
printf("select timeout!
");
break;
case -1:
perror("select return failed!
");
goto closesocket;
default:
if(FD_ISSET(clientfd, &readfds) > 0)
{
memset(buffer, 0, SIZE);
readlen = read(clientfd, buffer, SIZE);
if(readlen < 0)
{
perror("read data failed!
");
goto closesocket;
}
time(&timet);
printf("Opposite: %d %s", clientfd, ctime(&timet));
printf("客户端IP:%s
",htonl(INADDR_ANY));
printf("服务器实现者学号:20155332
");
printf("%s:%s
", "当前时间", ctime(&timet));
strcat(buffer, "
");
writelen = write(0, buffer, readlen+1);
if(writelen < 0)
{
perror("write data failed!
");
goto closesocket;
}
}
if(FD_ISSET(1, &readfds) > 0)
{
time(&timet);
/*printf("Owner: %d %s
", sockfd, ctime(&timet));*/
printf("客户端IP:%s
",htonl(INADDR_ANY));
printf("服务器实现者学号:20155332
");
printf("%s:%s
", "当前时间", ctime(&timet));
memset(buffer, 0, SIZE);
readlen = read(1, buffer, SIZE);
if(readlen < 0)
{
perror("read data failed!
");
goto closesocket;
}
writelen = write(clientfd, buffer, readlen);
if(writelen < 0)
{
perror("write data failed!
");
goto closesocket;
}
}
}
}
closesocket:
close(clientfd);
}
close(sockfd);
return 0;
}