TCP是一种面向连接的传输层协议,它能提供高可靠性通信
即数据无误、数据无丢失、数据无失序、数据无重复到达的通信
适合于对传输质量要求较高的通信,主要用于通讯软件用户登录账户管理等方面
流程 —基础版
服务器
socket:创建一个用与链接的套接字
头文件:
#include <sys/types.h>
#include <sys/socket.h>
格式int socket(int domain, int type, int protocol);
返回值
成功返回一个用于连接的文件描述符,失败返回-1;
int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 0 自动匹配协议
if (sockfd < 0)
{
perror("socket err.");
return -1;
}
填充通信结构体
struct sockaddr_in saddr,caddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(atoi(argv[1]));
//"8880" atoi函数:将数字字符转化为数值
//saddr.sin_addr.s_addr = inet_addr(argv[1]);
bind:绑定自己的ip地址和端口
头文件
#include <sys/types.h>
#include <sys/socket.h>
格式int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
返回值成功返回0,失败返回-1;
if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
{
perror("bind err.");
return -1;
}
listen:监听,将主动套接字转为被动套接字
头文件
#include <sys/types.h>
#include <sys/socket.h>
格式int listen(int sockfd, int backlog);
返回值成功返回0,失败返回-1;
if (listen(sockfd, 5) < 0)
{
perror("listen error.");
return -1;
}
accept:阻塞等待客户端链接,链接成功返回一个用于通信套接字
头文件
#include <sys/types.h>
#include <sys/socket.h>
格式int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
返回值成功返回一个用于通信的文件描述符,失败返回-1;
int acceptfd = accept(sockfd, (struct sockaddr *)&caddr, &len);
if (acceptfd < 0)
{
perror("accept err");
return -1;
}
recv:接收消息
头文件
#include <sys/types.h>
#include <sys/socket.h>
格式ssize_t recv(int sockfd, void *buf, size_t len, int flags);
返回值成功返回收到的字节数;另一边关闭时返回0;失败返回-1;
int ret = recv(acceptfd, buf, sizeof(buf), 0);
if (ret < 0)
{
perror("recv err.");
return -1;
}
else if (ret == 0)
{
printf("client exit.\n");
break;
}
else
{
printf("buf:%s\n", buf);
}
send:发送消息
头文件
#include <sys/types.h>
#include <sys/socket.h>
格式ssize_t send(int sockfd, const void *buf, size_t len, int flags);
返回值成功返回发送的字节数;失败返回-1;
send(sockfd,buf,sizeof(buf),0);
close:关闭文件描述符
头文件
#include <unistd.h>
格式int close(int fd);
返回值成功返回0;失败返回-1;
close(sockfd);
客户端:
socket:创建一个套接字
填充结构体:填充服务器的ip和端口
connect:阻塞等待链接服务器
头文件
#include <sys/types.h>
#include <sys/socket.h>
格式int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
返回值连接成功返回0;失败返回-1;
int d=connect(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
if(d<0)
{
perror("connect err。");
return -1;
}
recv/send:接收/发送消息
close:关闭
整体代码
服务器端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
//1.创建流式套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 0 自动匹配协议
if (sockfd < 0)
{
perror("socket err.");
return -1;
}
printf("socket ok:%d\n", sockfd);
//定义一个ipv4的通信结构体
struct sockaddr_in saddr,caddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(atoi(argv[1]));
//"8880" atoi函数:将数字字符转化为数值
//saddr.sin_addr.s_addr = inet_addr(argv[1]);//ip地址
//设置自动获取本机ip。
saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
socklen_t len=sizeof(caddr);
//2.绑定bind
if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
{
perror("bind err.");
return -1;
}
printf("bind ok.\n");
//3.监听 listen
if (listen(sockfd, 5) < 0)
{
perror("listen error.");
return -1;
}
printf("listen ok.\n");
while (1)
{
//4.阻塞等待链接,成功得到一个用于通信的文件描述符
int acceptfd = accept(sockfd, (struct sockaddr *)&caddr, &len);
if (acceptfd < 0)
{
perror("accept err");
return -1;
}
printf("accept ok %d\n", acceptfd);
printf("client ip = %s port=%d \n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));//通信 收
char buf[128];
while (1)
{
bzero(buf, sizeof(buf));
int ret = recv(acceptfd, buf, sizeof(buf), 0);
if (ret < 0)
{
perror("recv err.");
return -1;
}
else if (ret == 0)
{
printf("client exit.\n");
break;
}
else
{
printf("buf:%s\n", buf);
}
}
close(acceptfd);
}
close(sockfd);
return 0;
}
客户端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
if(argc != 3)
{
printf("please input %s <ip> <port>\n",argv[0]);
return -1;
}
//创建流式套接字
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd < 0)
{
perror("socket err.");
return -1;
}
printf("socket ok:%d\n",sockfd);
//填充服务器端ip和端口(ipv4)
struct sockaddr_in saddr;
saddr.sin_family=AF_INET;//通信类型 ipv4
saddr.sin_port=htons(atoi(argv[2]));
// atoi函数:将数字字符转化为数值
saddr.sin_addr.s_addr=inet_addr(argv[1]);
//请求连接服务器
int d=connect(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
if(d<0)
{
perror("connect err。");
return -1;
}
printf("connect ok \n");
//循环发送
char buf[128];
int ret;
while(1)
{
bzero(buf,sizeof(buf));
fgets(buf,128,stdin);
//实际获取的最大数据长度size-1,补'\0',
//遇到'\n'截至,同时会获取'\n'.
if (!strcmp("quit\n", buf))//可不用if,运行时直接用 ctrl +c退出
break;
if(buf[strlen(buf)-1] == '\n')
buf[strlen(buf)-1] = '\0';
send(sockfd,buf,sizeof(buf),0);
}
close(sockfd);
return 0;
}