1. send()
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能:
发送数据
参数:
sockfd:
文件描述符
服务器:
accept的返回值
客户端:
socket的返回值
buf:
要发送的数据
len:
发送的数据的长度
flags:
标志位
0 阻塞
MSG_DONTWAIT 非阻塞
返回值:
成功:
发送的字节数
失败:
-1
write(fd, buf, N)
<==>
send(fd, buf, N, 0)
<==>
sendto(fd, buf, N, 0, NULL, 0);
2. recv()
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能:
接收数据
参数:
sockfd:
文件描述符
服务器:
accept的返回值
客户端:
socket的返回值
buf:
保存接收到的数据
len:
接收的数据的长度
flags:
标志位
0 阻塞
MSG_DONTWAIT 非阻塞
返回值:
成功:
接收的字节数
失败:
-1
0 当发送端关闭套接字或者结束程序时,接收端会返回0
read(fd, buf, N)
<==>
recv(fd, buf, N, 0)
<==>
recvfrom(fd, buf, N, 0, NULL, NULL);
3. 相关代码
3.1 服务器
//TCP网络编程之服务器
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#define N 128
//__FILE__: 获取文件名
//__func__:获取函数名
//__LINE__:获取行号
#define ERRLOG(errmsg) do{\
perror(errmsg);\
printf("%s-%s-%d\n", __FILE__, __func__, __LINE__);\
exit(1);\
}while(0)
int main(int argc, char const *argv[])
{
if(argc < 3)
{
fprintf(stderr, "Usage: %s <ip> <port>\n", argv[0]);
exit(1);
}
int sockfd, acceptfd;
struct sockaddr_in serveraddr, clientaddr;
socklen_t addrlen = sizeof(struct sockaddr_in);
char buf[N] = {0};
ssize_t bytes;
//第一步:创建套接字
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
ERRLOG("socket error");
}
//第二步:填充服务器网络信息结构体
//inet_addr:将点分十进制ip地址转化为无符号32位整形数据
//htons:将主机字节序转化为网络字节序
//atoi:将数字型字符串转化为整形数据 "1568" --> 1568
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
serveraddr.sin_port = htons(atoi(argv[2]));
//第三步:将套接字与服务器网络信息结构体绑定
if(bind(sockfd, (struct sockaddr *)&serveraddr, addrlen) == -1)
{
ERRLOG("bind error");
}
//第四步:将套接字设置为被动监听状态
if(listen(sockfd, 5) == -1)
{
ERRLOG("listen error");
}
//第五步:阻塞等到客户端的连接
if((acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen)) == -1)
{
ERRLOG("accept error");
}
//输出客户端的信息
printf("[%s - %d]\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
//进行通信
while(1)
{
if((bytes = recv(acceptfd, buf, N, 0)) == -1)
{
ERRLOG("recv error");
}
else if(bytes == 0)
{
printf("客户端[%s - %d]退出了\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
exit(0);
}
if(strcmp(buf, "quit") == 0)
{
printf("客户端[%s - %d]退出了\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
exit(0);
}
printf("客户端[%s - %d]:%s\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port), buf);
strcat(buf, " ^_^");
//如果接收端退出或者关闭套接字,send函数在第二次执行时
//会产生SIGPIPE,默认对当前进程的处理方式是结束进程
if(send(acceptfd, buf, N, 0) == -1)
{