0814 TCP通信协议
Part 1.牛客网刷题
Part 2.思维导图
一.socket
1.作用
创建套接字函数
2.函数原型
int socket(int domain, int type, int protocol);
函数参数:
int domain:通信域
AF_UNIX, AF_LOCAL 本地通信 man 7 unix
AF_INET IPv4 man 7 ip
AF_INET6 IPv6 man 7 ipv6
int type:传输层协议类型
SOCK_STREAM TCP协议
OCK_DGRAM UDP协议
int protocol
0
二.bind
1.作用
给套接字文件设置地址
2.函数原型
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int sockfd:嵌套字函数文件描述符
const struct sockaddr *addr:地址信息结构体
对于IPv4(AF_INET ):
struct sockaddr_in
{
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
/* Internet address. */
struct in_addr
{
uint32_t s_addr; /* address in network byte order */
};
需要自己创建sockaddr_in类型的结构体,并对结构体进行赋值,最后往函数内传入结构体地址
对于本地通信(AF_UNIX):
struct sockaddr_un
{
sa_family_t sun_family; /* AF_UNIX */
char sun_path[108]; /* pathname */
};
socklen_t addrlen:结构体大小
三.listen
1.作用
将给定的套接字文件设为监听状态
2.函数原型
int listen(int sockfd, int backlog);
int sockfd:套接字文件文件描述符
int backlog:一次接收多少个客户端,等待队列的长度
四.accept
1.作用
在接收到客户端请求后创建一个新的套接字文件用来通信
2.函数原型
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数:
int sockfd:用于监听的套接字文件描述符
struct sockaddr *addr:接收客户套接字文件地址信息的指针
socklen_t *addrlen:客户套接字文件地址信息长度
五.connect
1.作用
发送到服务器端申请连接的请求
2.函数原型
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
参数:int sockfd:客户端套接字文件描述符
const struct sockaddr *addr:服务器端套接字文件地址信息的指针
socklen_t addrlen:服务器端套接字文件地址信息长度
Part 3.基于IPC通信的服务器端和客户端实现
1.service.c
#include<myhead.h>#define SER_PORT 8888//端口号
#define SER_IP "192.168.109.62"//IPint main(int argc, const char *argv[])
{//创建一个用于连接的套接字int sfd = socket(AF_INET,SOCK_STREAM,0);//创建一个IPv4&TCP的套接字文件if(-1 == sfd)ERR_MSG("socket error");//判断是否创建成功printf("socket success\n");//给套接字绑定IP地址和端口号struct sockaddr_in sin;//地址信息结构体变量//变量赋值sin.sin_family = AF_INET;//通信域地址族sin.sin_port = htons(SER_PORT);//端口号(将端口转为网络字节序)sin.sin_addr.s_addr = inet_addr(SER_IP);//IP地址(将IP地址转为网络字节序)//绑定if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin)) == -1)ERR_MSG("bind error");printf("bind success\n");//启动套接字监听if(listen(sfd,128) == -1)ERR_MSG("listen error");printf("listen success\n");//阻塞客户端,知道有用户端连接//创建一个用于连接的套接字文件struct sockaddr_in cin;socklen_t addrlen = sizeof(cin);//等待客户端连接,阻塞服务端int new_fd = accept(sfd,(struct sockaddr *)&cin,&addrlen);if(-1 == new_fd)ERR_MSG("accept error");printf("[%s:%d]发来连接 fd:%d\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),new_fd);//使用新套接字跟客户端进行通信while(1){//从套接字中读取消息char rbuf[128] = ""; //存放接受消息的容器int res = read(new_fd, rbuf, sizeof(rbuf)-1);if(res == 0){printf("客户端已下线\n");close(new_fd);break;}if(res == -1){perror("read error");close(new_fd);close(sfd);return -1;}printf("[%s:%d] : %s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), rbuf);strcat(rbuf, " 已读");//向套接字中写入消息write(new_fd, rbuf, strlen(rbuf));printf("发送成功\n");}//6、关闭监听套接字close(sfd);return 0;
}
2.client.c
#include<myhead.h>#define SER_PORT 8888 //服务器端口号
#define SER_IP "192.168.109.62" //服务器ip地址
#define CLIENT_PORT 9999 //客户端端口号
#define CLIENT_IP "192.168.109.62" //客户端ip地址int main(int argc, const char *argv[])
{//创建一个用于通信的套接字文件int cfd = socket(AF_INET,SOCK_STREAM,0);if(-1 == cfd)ERR_MSG("socket srror");printf("socket success\n");//连接服务器//创建封装服务器端信息结构体struct sockaddr_in sin;sin.sin_family = AF_INET; //通信域sin.sin_port = htons(SER_PORT); //服务器端口号sin.sin_addr.s_addr = inet_addr(SER_IP); //服务器ip地址//连接if(connect(cfd,(struct sockaddr *)&sin,sizeof(sin)) == -1)ERR_MSG("connect error");printf("connect success\n");//数据收发while(1){char wbuf[128] = ""; //用于发送数据的容器fgets(wbuf, sizeof(wbuf), stdin); //从终端获取消息wbuf[strlen(wbuf)-1] = '\0'; //将换行改成'\0'if(strcmp(wbuf, "quit") == 0){break;}//将数据发送给服务器write(cfd, wbuf, strlen(wbuf));printf("发送成功\n");//接收服务器发送的消息read(cfd, wbuf, sizeof(wbuf));printf("收到的消息为:%s\n", wbuf);}//5关闭套接字close(cfd);return 0;
}