TCP编程
TCP的编程步骤和UDP的有一定的差异,但是也有一些步骤是相同的,比如都需要创建套接字和绑定地址信息。下面我们就一起来看看TCP的编程步骤:
客户端:创建套接字、绑定地址信息(不推荐)、连接服务器、发送数据、接收数据、关闭套接字
服务端:创建套接字、绑定地址信息、监听、接收新连接、接收数据、发送数据、关闭套接字
和UDP相比,TCP编程多了一些步骤,而且除了创建套接字、绑定地址信息和关闭套接字的函数是一样的以外,其它的函数有一定的变化,这里我们就不再介绍相同的函数,大家可以点击这里找到相关内容。
连接服务器
函数原型:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数说明:
sockfd:客户端调用socket创建出来的套接字描述符
addr:要连接的服务端的地址信息
addrlen:地址信息的长度
返回值:成功返回0,失败返回-1
监听
函数原型:
#include <sys/socket.h>
int listen(int sockfd, int backlog);
参数解释:
sockfd:侦听套接字,socket函数的返回值
backlog:已完成连接队列的大小
对于backlog我们需要了解的是:当我们调用listen函数之后,就是告诉内核,当中程序可以接收新的连接了(也就是可以完成三次握手了的过程了)。三次握手是网络协议栈完成的事情,程序员不需要干预,连接过程是在内核中完成的,而目前正在处于三次握手的连接是保存在一个队列中的,已经完成连接的队列是保存在另一个队列中的。backlog就是已完成连接队列的大小。
接收新连接
函数原型:
#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数说明:
sockfd:侦听套接字,socket函数的返回值
addr:对端的地址信息,客户端的地址信息
addrlen:对端的地址信息,客户端地址信息长度
返回值:正常:返回的是为新连接创建出来的套接字
失败:小于0
发送数据
函数原型:
#include <sys/types.h>
#include <sys/socket.h>
int send(int sockfd, const void *msg, size_t len, int flags);
参数说明:
sockfd:客户端:客户端调用socket函数创建出来的套接字描述符
服务端:accept函数的返回值
msg:待发送的数据
len:发送数据的长度
flags:0 阻塞发送
返回值:成功返回发送的字符个数,失败返回-1
接收数据
函数原型:
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
参数说明:
sockfd:客户端:客户端调用socket函数创建出来的套接字描述符
服务端:accept函数的返回值
buf:接收数据缓冲区
len:最大接收能力
flags:0阻塞接收
返回值: 大于0:接收了多少字节数据
等于0:对端关闭了连接
小于0:接收失败
多个版本的TCP
单执行流
服务端:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
using namespace std;
int main()
{
//创建套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
perror("socket");
return -1;
}
//填充结构体
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(19898);
addr.sin_addr.s_addr = inet_addr("192.168.115.133");
//绑定地址信息
int ret = bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
if(ret < 0)
{
perror("bind");
return -1;
}
//侦听
int listenfd = listen(sockfd, 1);
if(ret < 0)
if(ret < 0)
{
perror("listen");
return -1;
}
//接收新连接
int new_sock = accept(sockfd,NULL, NULL);
if(new_sock < 0)
{
perror("accept");
return -1;
}
while(1)
{
//接收数据
char buf[1024] = {
0};
ssize_t recv_size = recv(new_sock,buf, sizeof(buf) - 1, 0);
if(recv_size < 0)
{
perror("recv");
continue;
}
else if(recv_size == 0)
{
cout << "perr shutdown" << endl;
close(new_sock);
close(sockfd);
return 0;
}
cout << "cli say:" &l