TCP服务器实现过程
-
创建套接字:socket函数
-
给套接字绑定IP地址和端口号:bind函数
-
将套接字文件描述符,从主动变为被动文件描述符(做监听准备):listen函数
主动描述符可以主动的向对方发送数据 被动描述符只能被动的等待别人主动向你发数据,然后再回答数据,不能主动的发送数据。
-
被动监听客户的连接并相应:accept函数
-
服务器调用read(recv)和write(send),收发数据,实现通信
绑定错误:先关客户端再关服务器(四次挥手,主动关闭的一方处于TIME_WAIT状态
解决:
int opt = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));)
套接字socket函数
-
函数原型
#include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol);
-
参数
domain:族/范围 (ip32位:IPV4, ip128位:IPV6)
type:套接字类型(可或)SOCK_STREAM: TCP SOCK_DGRAM: UDP SOCK_RDM: 原始网络通信 SOCK_NONBLCOK:以非阻塞方式通信
绑定IP地址和端口号bind函数
- 函数原型
#include <sys/types.h> #include <sys/socket.h> int bind(int sockfd; const struct sockaddr *addr, socklen_t addrlen);
- 参数
第一个参数位套接字id
第二个参数位保存ip和端口号的结构体 - 返回值: 成功返回0; 失败返回-1, errno被设置
字节序转化
- 网络字节序采用大端字节序
- 为什么要进行字节序转化(因为接收端为小端字节序)
- 字节序转化函数(ip地址格式转化)
int inet_aton(const char *cp, struct in_addr *inp)
char *inet_ntoa(stuct in_addr in)
listen函数
- 函数原型
#include<sys/types.h> #include<sys/socket.h> int listen(int sockfd, int backlog);
- 参数
sockfd: 套接字文件描述符
backlog: 指定队列的容量(<30) - 返回值:成功返回0;失败返回-1,errno被设置
accept函数
-
函数原型
#include<sys/types.h> #include<sys/socket.h> int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
-
参数
addr: 用于记录发起连接请求的那个客户的IP和端口(port) -
返回值:成功返回通信描述符 失败返回-1,errno被设置
TCP客户端的实现过程
- 创建套接字
- 调用connect主动向服务器发起三次握手,进行连接
- 调用read(recv)和write(send)收发数据
- 调用close或者shutdown关闭连接
connect函数
-
函数原型
#include<sys/types.h> #include<sys/socket.h> int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
-
参数
sockfd: 套接字文件描述符
addr: 用于设置你所要连接服务器的ip和端口如果只是纯粹的局域网内部通信的话,ip就是局域网ip,但如果是跨网通信的话,ip必须是服务器所在路由器的公网ip
-
返回值:成功返回0,失败返回-1;
文件通信实例
//server.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#define PORT 33333
int main()
{
int sockfd;
struct sockaddr_in addr;
int len = sizeof(struct sockaddr_in);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == -1)
{
perror("socket\n");
exit(1);
}
printf("server socket success!\n");
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
bzero(&addr, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = inet_addr("192.168.137.129");
if(bind(sockfd, (struct sockaddr *)&addr, len)<0)
{
perror("bind\n");
exit(1);
}
if(listen(sockfd, 3) < 0)
{
perror("listen\n");
exit(1);
}
printf("server bind success!\n");
while(1)
{
struct sockaddr_in c_addr;
bzero(&c_addr, sizeof(struct sockaddr_in));
printf("accepting.....!\n");
int cfd;
cfd = accept(sockfd, (struct sockaddr *)&c_addr, len);
if(cfd == -1)
{
perror("accept\n");
exit(1);
}
printf("ip = %s\n",inet_ntoa(c_addr.sin_addr));
char buf[1024];
memset(buf, 0, sizeof(buf));
read(cfd, buf, sizeof(buf));
usleep(2);
write(cfd, buf, strlen(buf));
}
return 0;
}
//client.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#define PORT 33333
int main()
{
int sockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == -1)
{
perror("sockfd");
exit(1);
}
printf("client socket success!\n");
struct sockaddr_in s_addr;
bzero(&s_addr, sizeof(struct sockaddr_in));
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(PORT);
s_addr.sin_addr.s_addr = inet_addr("192.168.137.129");
if(connect(sockfd, (struct sockaddr *)(&s_addr), sizeof(struct sockaddr_in))<0)
{
perror("connect\n");
exit(1);
}
printf("connect success!\n");
write(sockfd, "hello world\n", 13);
char buf[1024];
read(sockfd, buf, sizeof(buf));
printf("recv server:%s\n", buf);
return 0;
}