您的位置:首页 > 理论基础 > 计算机网络

linux select()详解( 三)-- TCP最简实例

2016-06-04 18:21 423 查看
通过本文你会了解到:

1. TCP server的实例

2. TCP client的实例

3. TCP server和client的运行测试

4. TCP C/S模型的思考

约定

1. 格式为 /**/ 的注释对程序的主要流程进行说明

2. 格式为 // 的注释对程序的难懂语句进行说明

TCP server实例(server.c)

#include <stdio.h>      /* for printf() and fprintf() */
#include <sys/types.h>  /* for Socket data types */
#include <sys/socket.h> /* for socket(), connect(), send(), and recv() */
#include <netinet/in.h> /* for IP Socket data types */
#include <arpa/inet.h>  /* for sockaddr_in and inet_addr() */
#include <stdlib.h>     /* for exit() */
#include <string.h>     /* for memset() */
#include <unistd.h>     /* for close() */
#include <errno.h>      /* for errno*/

//macro
#define BUF_SIZE 1024
#define PORT 1025
#undef max
#define max(x, y) ((x) > (y) ? (x) : (y))
#undef handle_error
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while(0)

int main(int argc, char *argv[])
{
struct sockaddr_in server_addr;
struct sockaddr_in conn_addr;
fd_set read_fds;
socklen_t len;
char buf[BUF_SIZE];
int conn_fd = -1;
int server_fd = -1;
int ret;

/*创建tcp描述符*/
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if(server_fd == -1)
handle_error("socket");

/*指定server信息并绑定*/
memset(&server_addr, 0, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); //ip地址为任意,只要port满足即可

if(bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
handle_error("bind");

/*监听server描述符*/
if(listen(server_fd, 5) == -1)
handle_error("listen");

printf("accepting connections on port %d\n", PORT);
while(1) {
int max_fd = 0;

FD_ZERO(&read_fds);
FD_SET(server_fd ,&read_fds);
max_fd = max(server_fd, max_fd);
if(conn_fd > 0) {
FD_SET(conn_fd ,&read_fds);
max_fd = max(conn_fd, max_fd);
}
/*检测描述符集中的描述符的I/O状态*/
ret = select(max_fd + 1, &read_fds, NULL, NULL, NULL);

if(ret == -1 && errno == EINTR)
continue;

if(ret == -1)
handle_error("select");

if(FD_ISSET(server_fd, &read_fds)) { //server_fd可读,即有client连接
len = sizeof(conn_addr);
if(conn_fd > 0) { //如果已有连接,则先关闭,因此此server只与最后一次连接的client进行通信
close(conn_fd);
}
/*接受并得到client信息*/
conn_fd = accept(server_fd, (struct sockaddr *)&conn_addr, &len);
if(conn_fd == -1)
handle_error("accept");
printf("client is connected\n");

} else if(FD_ISSET(conn_fd, &read_fds)) { //conn_fd可读,即接收到client数据
int n;
memset(buf, 0, BUF_SIZE);
n = recv(conn_fd, buf, BUF_SIZE, 0);
if(n == -1) { //recv函数返回错误
perror("recv");
close(conn_fd);
conn_fd = -1;
} else if(n == 0) { //client端套接字被关闭
printf("client is closed\n");
close(conn_fd);
conn_fd = -1;
} else { //读取成功
/*对收到的数据进行处理*/
printf("receive data:%s\n", buf);
}
}
}

/*关闭描述符*/
close(server_fd);

return 0;
}


TCP client实例(client.c)

#include <stdio.h>      /* for printf() */
#include <sys/types.h>  /* for Socket data types */
#include <sys/socket.h> /* for socket(), connect(), send(), and recv() */
#include <netinet/in.h> /* for IP Socket data types */
#include <arpa/inet.h>  /* for sockaddr_in and inet_addr() */
#include <stdlib.h>     /* for exit() */
#include <string.h>     /* for memset() */
#include <unistd.h>     /* for close() */
#include <errno.h>      /* for errno*/

//macro
#define BUF_SIZE 1024
#define PORT 1025
#define SEND_PACK_CNT 3
#define SRV_IP "127.0.0.1"
#undef handle_error
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while(0)

int main(int argc, char *argv[])
{
struct sockaddr_in server_addr;
char buf[BUF_SIZE];
int conn_fd = -1;
int i;

/*创建tcp描述符*/
conn_fd = socket(AF_INET, SOCK_STREAM, 0);
if(conn_fd == -1)
handle_error("socket");

/*指定将连接的server信息*/
memset(&server_addr, 0, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
if (inet_aton(SRV_IP, &server_addr.sin_addr) == 0)
handle_error("inet_aton");

/*连接到server*/
if(connect(conn_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
handle_error("connect");

printf("connect to server ip:%s port:%d\n", SRV_IP, PORT);
for(i = 0; i < SEND_PACK_CNT; i++) {
sprintf(buf, "Packet %d", i);
printf("send to server: %s\n", buf);
/*发送数据*/
send(conn_fd, buf, strlen(buf) + 1, 0);
sleep(2);
}

/*关闭描述符*/
printf("close\n");
close(conn_fd);

return 0;
}


TCP server和client的运行测试



TCP C/S模型的思考

在TCP连接关闭时,连接会进入TIME_WAIT状态,经过2个MSL时间后关闭,因此如果client频繁连接和关闭,如果在2个MSL时间内令连接数达到1024则下一次将会返回失败。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: