C语言实现TCP编程
TCP编程流程1.主机字节序和网络字节序2.套接字的地址结构IP地址转化的方法3. TCP的网络接口4. TCP服务器端的编程流程5. TCP客户端的编程流程6.运行结果1.主机字节序和网络字节序主机字节序: 不同的芯片,所采用的数值存储方式是不同:大端模式&小端模式网络字节序: 统一使用大端模式来表示数据2.字节序的转化#include <netinet/in.h>uint3
·
1.主机字节序和网络字节序
主机字节序: 不同的芯片,所采用的数值存储方式是不同:大端模式&小端模式
网络字节序: 统一使用大端模式来表示数据
2.字节序的转化
#include <netinet/in.h>
uint32_t ntohl (uint32_t __netlong); // 网络字节序转化为 主机字节序 long
uint16_t ntohs (uint16_t __netshort); // 网络字节序转化为主机字节序 short
uint32_t htonl (uint32_t __hostlong); // 主机字节序转化为网络字节序 long
uint16_t htons (uint16_t __hostshort); // 主机字节序转化 为网络字节序 short
2.套接字的地址结构
运行在两个不同主机上的进程想要通信: 必须知道 IP地址 端口号
// 通用的地址结构
struct sockaddr
{
sa_family_t sa_family;
char sa_data[14];
};
// IPV4 专有的地址结构
struct sockaddr_in
{
sa_family_t sin_family; // 地址簇 AF_INET
uint16_t sin_port; // 端口号: 将主机字节序转化为网络字节序 0--1024 系统预留 1025 -- 4096 知名端口号 4097 --
65535
struct in_addr sin_addr;
};
struct in_addr
{
uint32_t s_addr; // IP地址 以字符串形式来表示一个点分十进制。 IP地址的转化
};
IP地址转化的方法
uint32_t inet_addr (const char *__cp); // 将点分十进制的字符串转化为uint32_t类型
char * inet_ntoa (struct in_addr __in); // 将struct in_addr类型的变量转化为char*字符串
3. TCP的网络接口
/*
创建socket套接字
返回值: 成功返回文件描述符 socket 失败返回-1
domain: 协议簇 AF_INET TCP/IP协议
type: 具体的协议 SOCK_STREAM --> tcp SOCK_DGRAM --> UDP
protocol: 在前两个值的协议基础下的一个具体协议,一般默认设置为0
*/
int socket (int __domain, int __type, int __protocol);
/*
命令(绑定)socket套接字
返回值: 成功返回0, 失败返回-1
fd: socket方法返回的套接字的文件描述符
addr: 服务器的地址结构变量的地址 需要类型强转
len: addr的长度
*/
int bind (int __fd, struct sockaddr * __addr, socklen_t __len);
/*
启动监听方法
返回值: 成功返回0, 失败返回-1
fd: socket方法返回的套接字的文件描述符
n: 内核创建的用于维护已完成连接的客户端的个数: n+1
*/
int listen (int __fd, int __n);
/*
获取一个连接
返回值: 成功返回描述这个连接的文件描述符, 失败返回-1
fd: socket创建的文件描述符
addr: 用于保存客户端的地址信息
addr_len: addr的长度
*/
int accept (int __fd, struct sockaddr * __addr, socklen_t *__addr_len);
/*
读取数据
fd: 需要读取数据的文件描述符
buf: 读取的数据存储的缓冲区的首地址
n: 一次能够读取的数据长度,单位是字节
flag: 标志,默认给0
*/
ssize_t recv (int __fd, void *__buf, size_t __n, int __flags);
/*
发送数据
fd: 需要写入数据的文件描述符
buf: 写入的数据存储的缓冲区的首地址
n: 一次写入的真实数据长度,单位是字节
flag: 标志,默认给0
*/
ssize_t send (int __fd, const void *__buf, size_t __n, int __flags);
/*
发起连接的方法 -- 客户端程序使用
返回值: 成功返回0, 失败返回-1
fd: socket创建的文件描述符
addr: 服务器的地址信息
len: addr的长度
*/
int connect (int __fd, struct sockaddr * __addr, socklen_t __len);
// 关闭一个文件描述符
int close(int __fd);
4. TCP服务器端的编程流程
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main()
{
//创建用于监听的套接字,这个套接字是一个文件描述符,用于检测有没有客户端发起一个新的连接
int listenfd = socket(AF_INET,SOCK_STREAM,0);
assert(listenfd != -1);
struct sockaddr_in addr;
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port =htons(6000);//转化端口号
addr.sin_addr.s_addr = inet_addr("127.0.0.1");//回环地址
// 将得到的监听的文件描述符和本地的IP端口进行绑定
int res = bind(listenfd,(struct sockaddr*)&addr,sizeof(addr));
assert(res != -1);
//设置监听(成功之后开始监听,监听的是客户端的连接)
res = listen(listenfd,5);
assert(res != -1);
//通信
while (1)
{
struct sockaddr_in cli_addr;
socklen_t cli_len = sizeof(cli_addr);
int c = accept(listenfd,(struct sockaddr*)&cli_addr,&cli_len);
if(c == -1)
{
printf("Get One Client Link Error\n");
continue;
}
while (1)
{
char buff[128] = {0};
int n = recv(c,buff,127,0);//读取数据放在buff中,一次读取127个
if(n <= 0)
{
printf("Client will unlink\n");
break;
}
printf("%d : %s\n",c,buff);
send(c,"OK",2,0);
}
close(c);
}
//断开连接,关闭套接字(四次挥手)
close(listenfd);
return 0;
}
5. TCP客户端的编程流程
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main()
{
//创建一个通信的套接字,需要指定服务器的IP和端口号y
int sockfd = socket(AF_INET,SOCK_STREAM,0);
assert(sockfd != -1);
struct sockaddr_in ser_addr;
memset(&ser_addr,0,sizeof(ser_addr));
ser_addr.sin_family = AF_INET;
ser_addr.sin_port =htons(6000);//转化端口号
ser_addr.sin_addr.s_addr = inet_addr("127.0.0.1");//回环地址
//连接服务器,需要知道服务器绑定的IP和端口
int res = connect(sockfd,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
assert(res != -1);
//通信
while (1)
{
printf("input: ");
char buff[128] = {0};
fgets(buff,127,stdin);
if(strncmp(buff,"end",3) == 0)
{
break;
}
send(sockfd,buff,strlen(buff) - 1,0);//\n不发
memset(buff,0,128);
recv(sockfd,buff,127,0);
printf("%s\n",buff);
}
//断开连接
close(sockfd);
return 0;
}
6.运行结果
更多推荐
所有评论(0)