- TCP客户端和服务器通信
- 流程
- 字节序转换函数
- IP地址转换的函数:
- 将套接字和网络信息结构体绑定bind
- 代码实现
- 01server.c
- 02client.c
- 执行结果
- 6. 非原创
- 基于C语言实现,TCP练习——用read-write
-
服务器:
1.创建流式套接字 socket
2.填充服务器的网络信息结构体
3.将网络信息结构体和套接字进行绑定 bind
4.将套接字设置成被动监听状态 listen
5.阻塞等待客户端连接 accept
6.收发数据 read/write
7.关闭套接字 close -
客户端:
1.创建流式套接字 socket
2.填充服务器的网络信息结构体
3.与服务器建立连接 connect
4.收发数据 read/write
5.关闭套接字 close
- 主机字节序到网络字节序
h host 主机
n net 网络
将无符号4字节整型 从主机-->网络 uint32_t htonl(uint32_t hostlong);
将无符号2字节整型 从主机-->网络 uint16_t htons(uint16_t hostshort);
- 网络字节序到主机字节序
将无符号4字节整型 从网络-->主机 uint32_t ntohl(uint32_t netlong);
将无符号2字节整型 网络-->主机 uint16_t ntohs(uint16_t netshort);IP地址转换的函数:
- inet_addr()
将strptr所指的字符串转换成32位的网络字节序二进制值。 in_addr_t inet_addr(const char*strptr);
- inet_ntoa()
将32位网络字节序二进制地址转换成点分十进制的字符串。 char *inet_ntoa(stuct in_addr inaddr);将套接字和网络信息结构体绑定bind
- 网络信息结构体 sockaddr
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
只用于强制类型转换,防止编译器警告
- sockaddr_in / in_addr
struct sockaddr_in {
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
};
struct in_addr {
uint32_t s_addr;
};
代码实现
01server.c
#include02client.c#include #include #include #include #include #include #include #include #include #include #include #include int main(int argc, char const *argv[]) { // 1.创建流式套接字 // socket返回的文件描述符 int sockfd = 0; // IPV4使用,//TCP if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket error"); exit(-1); } // 2.填充服务器的网络信息结构体 struct sockaddr_in addr; //清空、填充0 memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; // IPV4 //端口号 //将无符号2字节整型 主机-->网络 addr.sin_port = htons(8888); // ip地址 //将strptr所指的字符串转换成32位的网络字节序二进制值。 addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //结构体长度 socklen_t addr_len = sizeof(addr); // 3.将网络信息结构体和套接字进行绑定 bind //强制类型转换 if (bind(sockfd, (struct sockaddr *)&addr, addr_len) == -1) { perror("connect error"); exit(-1); } // 4.将套接字设置成被动监听状态 listen if (-1 == listen(sockfd, 5)) { perror("listen error"); exit(-1); } // 5.阻塞等待客户端连接 accept //返回一个新的文件描述符,专门用于和该客户端通信 int accept_fd = 0; printf("等待客户端n"); if ((accept_fd=accept(sockfd, NULL, NULL))==-1) { perror("accept error"); exit(-1); } printf("客户端连接成功n"); while (1) { char buf[128] = {0}; //收 printf("客户端 > "); fflush(stdout); read(accept_fd, buf, 128); //printf("客户端 > %sn", buf); printf("%sn", buf); //将"996"(包括' ')追加到buf后面,会覆盖buf的' ' //strcat(buf, "996"); if (strcmp(buf,"quit")==0) { //关闭文件描述符 close(sockfd); close(accept_fd); break; } //发 printf("input > "); memset(buf, 0, sizeof(buf)); scanf("%s", buf); write(accept_fd, buf, 128); if (strcmp(buf,"quit")==0)//break; { //关闭文件描述符 close(sockfd); close(accept_fd); break; } } //关闭文件描述符 close(sockfd); close(accept_fd); return 0; }
#include执行结果 6. 非原创#include #include #include #include #include #include #include #include #include #include #include #include int main(int argc, char const *argv[]) { // 1.创建流式套接字 // socket返回的文件描述符 int sockfd = 0; // IPV4使用,//TCP if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket error"); exit(-1); } // 2.填充服务器的网络信息结构体 struct sockaddr_in addr; //清空、填充0 memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; // IPV4 //端口号 //将无符号2字节整型 主机-->网络 addr.sin_port = htons(8888); // ip地址 //将strptr所指的字符串转换成32位的网络字节序二进制值。 addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //结构体长度 socklen_t addr_len = sizeof(addr); //3.与服务器建立连接 connect //强制类型转换 if(-1 == connect(sockfd, (struct sockaddr *)&addr, addr_len)){ perror("connect error"); exit(-1); } while (1) { char bu[128] = {0}; //发 printf("input > "); scanf("%s", bu); write(sockfd, bu, 128); if (strcmp(bu,"quit")==0)//break; { //关闭文件描述符 close(sockfd); break; } //收 memset(bu, 0, sizeof(bu)); printf("服务器 > "); fflush(stdout); read(sockfd, bu, 128); //printf("服务器 > %sn", bu); printf("%sn", bu); if (strcmp(bu,"quit")==0)//break; { //关闭文件描述符 close(sockfd); break; } } //关闭文件描述符 close(sockfd); return 0; }



