1.tcp服务端
|
#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <netinet/tcp.h> #include <sys/socket.h> #include <net/if.h> #include <arpa/inet.h> #include <termios.h> /*PPSIX 终端控制定义*/ #define CREATE_TURE 1 #define CREATE_FALSE 0 /* * @description : 检测TCP服务端连接状态 * @param - fd : 文件描述符 * @return : 执行结果 链接断返回-1 正常返回0 */ int func_detect_tcp_server_link(int fd) { int info_len = 0, re_err = 0; struct tcp_info info; info_len = sizeof(struct tcp_info); getsockopt(fd, IPPROTO_TCP, TCP_INFO, (void *)&info, (socklen_t *)&info_len); if (info.tcpi_state != TCP_ESTABLISHED) { re_err = -1; } return re_err; } /* * @description : 建立TCP服务端监听 * @param - *fd : 监听文件描述符 * @param - listen_port: 监听端口 * @return : 执行结果 创建失败返回-1 正常返回0 */ int func_create_tcp_server_listen(int *fd, unsigned int listen_port) { int value = 0, Flags = 0; struct sockaddr_in servaddr; /*(1) 创建套接字*/ if ((*fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { return -1; } //设置为非阻塞 Flags = fcntl(*fd, F_GETFL, 0); fcntl(*fd, F_SETFL, Flags | O_NONBLOCK); setsockopt(*fd, SOL_SOCKET, SO_REUSEADDR, &Flags, sizeof(int)); /*(2) 设置服务器sockaddr_in结构*/ bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // servaddr.sin_port = htons(listen_port); /*(3) 绑定套接字和端口*/ if (bind(*fd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)) == -1) { printf("Bind error%s\n", strerror(errno)); value = -1; return value; } /*(4) 监听客户请求*/ if (listen(*fd, 10) < 0) { printf("listen error%s\n", strerror(errno)); value = -1; return value; } value = 1; return value; } /* * @description : TCP服务端与客户端建立链接 * @param - listen_fd: 监听文件描述符 * @param - *fd : 链接文件描述符 * @param - *ip : 客户端ip,用于ip过滤 * @return : 执行结果 无错误返回1 出现错误返回-1 */ int func_tcp_server_accept(int listen_fd, int *fd, char *ip) { struct sockaddr_in clientddr; socklen_t clilen = 0; int tempfd = 0, Flags = 0, value = 0; char temp_ip[16] = {0}; unsigned int temp_port; bzero(&clientddr, sizeof(clientddr)); clilen = sizeof(clientddr); //检测跟客户端建立链接是否成功 if ((tempfd = accept(listen_fd, (struct sockaddr *)&clientddr, &clilen)) < 0) { return value; } //检测建立链接的客户端IP是否与设置的相同,此处不判别,将接收所有IP请求建立链接。 memcpy(temp_ip, inet_ntoa(clientddr.sin_addr), 16); temp_port = ntohs(clientddr.sin_port); printf("client: IP=%s, port=%d\n", temp_ip, temp_port); if (memcmp(ip, temp_ip, 16) != 0) { close(tempfd); return value; } if (*fd > 0) { close(*fd); } //设置为非阻塞 Flags = fcntl(tempfd, F_GETFL, 0); fcntl(tempfd, F_SETFL, Flags | O_NONBLOCK); *fd = tempfd; value = 1; return value; } /* * @description : TCP服务端接收数据函数 * @param - fd : 链接文件描述符 * @param - *p_receive_buff: 接收数据缓冲区首地址 * @param - count: 最大接收长度 * @return : 实际接收数据长度 */ int func_tcp_server_receive(int fd, char *p_receive_buff, int count) { int receive_numb = 0; memset(p_receive_buff, 0x0, count); receive_numb = recv(fd, p_receive_buff, count, 0); return receive_numb; } /* * @description : TCP服务端发送数据函数 * @param - fd : 链接文件描述符 * @param - *p_send_buff: 发送数据缓冲区首地址 * @param - count: 发送数据长度 * @return : 实际发送数据长度 */ int func_tcp_server_send(int fd, char *p_send_buff, int count) { int send_numb = 0; if (func_detect_tcp_server_link(fd) != 0) { /*发送数据之前先检查链接状态*/ printf("ReadCwnd judge connect break\n"); return -1; } send_numb = write(fd, p_send_buff, count); if (count != send_numb) { printf("server terminated prematurely write err\n"); return -1; } return send_numb; } /* * @description : 主函数 * @return : 执行结果 */ int main(int argc, char *argv[]) { char receive_buff[20]; char send_buff[20] = "server test network"; int receive_num = 0; unsigned int establish_listen = CREATE_FALSE; int sockfd, listenfd; int result = 0; int real_send_num = 0; while (1) { if (establish_listen == CREATE_FALSE) { // TCP做服务端,建立监听 result = func_create_tcp_server_listen(&listenfd, 2404); if (result > 0) { establish_listen = CREATE_TURE; printf("tcp create server listen ok\n"); } else { if (listenfd > 0) { close(listenfd); } } } else { //接受客户端建立链接 result = func_tcp_server_accept(listenfd, &sockfd, "192.168.0.2"); if (result > 0) { printf("tcp connected\n"); break; } } } while (1) { //接收数据 receive_num = func_tcp_server_receive(sockfd, receive_buff, sizeof(receive_buff)); if (receive_num > 0) { printf("[nread= %d] = %s\n", receive_num, receive_buff); //发送数据 real_send_num = func_tcp_server_send(sockfd, send_buff, sizeof(send_buff)); if (real_send_num > 0) { printf("[nwrite=%d] = %s\n", real_send_num, send_buff); } else { close(sockfd); printf("tcp server disconnect"); break; } } usleep(1000); // 1ms } exit(0); } |
服务端仍然是按照如下顺序进行编写:
socket()//创建套接字;
bind()//分配套接字地址;
listen()//等待连接请求状态;
accept()//允许连接;
read()/write()//进行数据交换;
close()//断开连接;
需要注意我们在检测建立链接的客户端IP是否与设置的相同时没有做判别,将接收所有IP请求建立链接。下面我们看下详细解释:
func_detect_tcp_server_link(int fd): 检测 TCP 服务端连接状态的函数。它接受一个文件描述符 fd,通过调用 getsockopt 函数获取与该文件描述符相关的 TCP 连接信息,并判断连接状态是否为已建立(TCP_ESTABLISHED)。如果连接状态为已建立,则返回 0;否则返回-1。
func_create_tcp_server_listen(int *fd, unsigned int listen_port): 建立 TCP 服务端监听的函数。它接受一个指向监听文件描述符的指针 fd,以及监听的端口号 listen_port。函数首先创建一个套接字,并将其设置为非阻塞模式。然后,通过调用 bind 函数将套接字绑定到指定的端口上,并通过调用 listen 函数开始监听客户端请求。如果操作成功,返回 0;否则返回-1。
func_tcp_server_accept(int listen_fd, int *fd, char *ip): TCP 服务端与客户端建立连接的函数。它接受一个监听文件描述符 listen_fd,一个指向连接文件描述符的指针 fd,以及一个用于 IP 过滤的客户端 IP 地址 ip。函数通过调用 accept 函数接受客户端的连接请求,并检查建立连接的客户端 IP 是否与设置的 IP 相同。如果 IP 相同,将连接文件描述符赋值给 fd,并返回1;否则返回0。
func_tcp_server_receive(int fd, char *p_receive_buff, int count): TCP 服务端接收数据的函数。它接收一个连接文件描述符 fd,一个指向接收数据缓冲区的指针 p_receive_buff,以及最大接收长度 count。函数通过调用 recv 函数接收数据,并返回实际接收到的数据长度。
func_tcp_server_send(int fd, char *p_send_buff, int count): TCP 服务端发送数据的函数。它接收一个连接文件描述符 fd,一个指向发送数据缓冲区的指针 p_send_buff,以及发送数据的长度 count。函数首先调用 func_detect_tcp_server_link 函数检测连接状态,如果连接已断开,则返回 -1。然后通过调用 write 函数将数据发送给客户端,并返回实际发送的数据长度。如果发送的数据长度与指定的长度不一致,表示发送过程中出现错误,返回-1。
2.tcp客户端
|
#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <netinet/tcp.h> #include <sys/socket.h> #include <net/if.h> #include <arpa/inet.h> #include <termios.h> /*PPSIX 终端控制定义*/ #define CONNECT 1 #define DISCONNECT 0 /* * @description : 检测TCP客户端连接状态 * @param - fd : 文件描述符 * @return : 执行结果 链接断返回-1 正常返回0 */ int func_detect_tcp_client_link(int fd) { int info_len = 0, re_err = 0; struct tcp_info info; info_len = sizeof(struct tcp_info); getsockopt(fd, IPPROTO_TCP, TCP_INFO, (void *)&info, (socklen_t *)&info_len); if (info.tcpi_state != TCP_ESTABLISHED) { re_err = -1; } return re_err; } /* * @description : TCP客户端与服务端建立链接 * @param - *fd : 链接文件描述符 * @param - *ip : 服务端ip, * @param - port : 服务端端口, * @return : 执行结果 链接成功返回0 连接失败返回-1 */ int func_create_tcp_client_link(int *fd, char *ip, unsigned int port) { int value = 0, Flags = 0; struct sockaddr_in servaddr; fd_set set; struct timeval timeout; //设置建立连接等待时间 timeout.tv_sec = 30; timeout.tv_usec = 0; /*(1) 创建套接字*/ if ((*fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { value = -1; return value; } /*(2) 设置链接服务器地址结构*/ bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = inet_addr(ip); servaddr.sin_port = htons(port); //设置为非阻塞 Flags = fcntl(*fd, F_GETFL, 0); fcntl(*fd, F_SETFL, Flags | O_NONBLOCK); /*(3) 发送链接服务器请求*/ if (connect(*fd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { FD_ZERO(&set); FD_SET(*fd, &set); if (select((*fd) + 1, NULL, &set, NULL, &timeout) > 0) { if (func_detect_tcp_client_link(*fd) == -1) return -1; else value = 0; } else { value = -1; return value; } } return value; } /* * @description : TCP客户端接收数据函数 * @param - fd : 链接文件描述符 * @param - *p_receive_buff: 接收数据缓冲区首地址 * @param - count: 最大接收长度 * @return : 实际接收数据长度 */ int func_tcp_client_receive(int fd, char *p_receive_buff, int count) { int receive_numb = 0; memset(p_receive_buff, 0x0, count); receive_numb = recv(fd, p_receive_buff, count, 0); return receive_numb; } /* * @description : TCP客户端发送数据函数 * @param - fd : 链接文件描述符 * @param - *p_send_buff: 发送数据缓冲区首地址 * @param - count: 发送数据长度 * @return : 实际发送数据长度 */ int func_tcp_client_send(int fd, char *p_send_buff, int count) { int send_numb = 0; if (func_detect_tcp_client_link(fd) != 0) { printf("ReadCwnd judge connect break\n"); return -1; } send_numb = write(fd, p_send_buff, count); if (count != send_numb) { printf("server terminated prematurely write err\n"); return -1; } return send_numb; } /* * @description : 主函数 * @return : 执行结果 */ int main() { char receive_buff[20]; char send_buff[20] = "client test network"; unsigned int connect_state = DISCONNECT; int real_send_num = 0; int receive_num = 0; int sockfd; int result = 0; if (connect_state == DISCONNECT) { // TCP做客户端,主动跟服务端建立链接 result = func_create_tcp_client_link(&sockfd, "192.168.0.1", 2404); if (result >= 0) { connect_state = CONNECT; printf("tcp connected\n"); } } while (1) { if (connect_state == CONNECT) { //发送数据 real_send_num = func_tcp_client_send(sockfd, send_buff, sizeof(send_buff)); if (real_send_num > 0) { printf("[nwrite=%d] = %s\n", real_send_num, send_buff); sleep(1); //接收数据 receive_num = func_tcp_client_receive(sockfd, receive_buff, sizeof(receive_buff)); if (receive_num > 0) { printf("[nread= %d] = %s\n", receive_num, receive_buff); } } else { connect_state = DISCONNECT; printf("tcp client disconnect"); close(sockfd); } } else break; } exit(0); } |
func_detect_tcp_client_link(int fd): 检测 TCP 客户端连接状态的函数。它通过获取套接字的 TCP 状态信息,判断连接是否已经建立。如果连接状态为 TCP_ESTABLISHED(已建立连接),则返回 0;否则返回 -1。
func_create_tcp_client_link(int *fd, char *ip, unsigned int port): TCP 客户端与服务端建立连接的函数。它接受一个指向文件描述符的指针 fd,一个服务端 IP 地址字符串 ip,以及服务端端口号 port。函数首先创建一个套接字,然后设置服务器地址结构,尝试与服务端建立连接。如果连接成功,返回 0;连接失败返回 -1。
func_tcp_client_receive(int fd, char *p_receive_buff, int count): TCP 客户端接收数据的函数。它接收一个文件描述符 fd,一个指向接收数据缓冲区的指针 p_receive_buff,以及最大接收长度 count。函数通过调用 recv 函数接收数据,并返回实际接收到的数据长度。
func_tcp_client_send(int fd, char *p_send_buff, int count): TCP 客户端发送数据的函数。它接收一个文件描述符 fd,一个指向发送数据缓冲区的指针 p_send_buff,以及发送数据长度 count。函数首先调用 func_detect_tcp_client_link 检测连接状态,如果连接断开,则返回 -1。否则,调用 write 函数发送数据,并返回实际发送的数据长度。
141

被折叠的 条评论
为什么被折叠?



