一、tcp编程
注意
1.数据本身有顺序
2.发送和接收次数不需要对应
1. C/S 模式
==》服务器/客户端模型
server:socket()-->bind()--->listen()-->accept()-->recv()-->close()
client:socket()-->connect()-->send()-->close();
int on = 1;
setsockopt(listfd, SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
2. 服务器端
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
1)socket()
int socket(int domain, int type, int protocol);
功能:程序向内核提出创建一个基于内存的套接字描述符
参数:domain 地址族,PF_INET == AF_INET ==>互联网程序
PF_UNIX == AF_UNIX ==>单机程序
type 套接字类型:
SOCK_STREAM 流式套接字 ===》TCP
SOCK_DGRAM 用户数据报套接字===>UDP
SOCK_RAW 原始套接字 ===》IP
protocol 协议 ==》0 表示自动适应应用层协议。
返回值:成功 返回申请的套接字id
失败 -1;
2)bind()
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
功能:如果该函数在服务器端调用,则表示将 参数1相关的文件描述符文件 与参数2指定的接口地址关联,用于从该接口接受数据。
如果该函数在客户端调用,则表示要将 数据从参数1所在的描述符中 取出 并从 参数2所在的接口设备上 发送出去。
注意:如果是客户端,则该函数可以省略,由默认接口发送数据。
参数:sockfd 之前通过socket函数创建的文件描述符,套接字id
my_addr 是物理接口的结构体指针。表示该接口的信息
struct sockaddr 通用地址结构
{
u_short sa_family; 地址族
char sa_data[14]; 地址信息
};
转换成网络地址结构如下:
struct _sockaddr_in ///网络地址结构
{
u_short sin_family; 地址族
u_short sin_port; ///地址端口
struct in_addr sin_addr; ///地址IP
char sin_zero[8]; 占位
};
struct in_addr
{
in_addr_t s_addr;
}
socklen_t addrlen: 参数2 的长度。
返回值:成功 0
失败 -1;
3)listen()
int listen(int sockfd, int backlog);
功能:在参数1所在的套接字id上监听等待链接。
参数:sockfd 套接字id
backlog 允许链接的个数
返回值:成功 0
失败 -1;
4)accept()
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:从已经监听到的队列中取出有效的客户端链接并接入到当前程序。
参数:sockfd 套接字id
addr 如果该值为NULL ,表示不论客户端是谁都接入。
如果要获取客户端信息,则事先定义变量并传入变量地址,函数执行完毕将会将客户端
信息存储到该变量中。
addrlen 参数2的长度,如果参数2为NULL,则该值也为NULL;
如果参数不是NULL,&len,
一定要写成len = sizeof(struct sockaddr);
返回值:成功 返回一个用于通信的新套接字id;
从该代码之后所有通信都基于该id
失败 -1;
5)接收函数/发送函数
read()/write () ///通用文件读写,可以操作套接字。
recv(,0) /send(,0) ///TCP 常用套机字读写
recvfrom()/sendto() ///UDP 常用套接字读写
ssize_t recv(int sockfd, void *buf, size_t len,int flags);
功能:从指定的sockfd套接字中以flags方式获取长度为len字节的数据到指定的buff内存中。
参数:sockfd 如果服务器则是accept的返回值的新fd
如果客户端则是socket的返回值旧fd
buff 用来存储数据的本地内存,一般是数组或者动态内存。
len 要获取的数据长度
flags 获取数据的方式,0 表示阻塞接受
返回值:成功 表示接受的数据长度,一般小于等于len
失败 -1;
6)close()
===>关闭指定的套接字id;
3. 客户端
1)connect()
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:该函数固定有客户端使用,表示从当前主机向目标主机发起链接请求。
参数:sockfd 本地socket创建的套接子id
addr 远程目标主机的地址信息
addrlen 参数2的长度
返回值:成功 0
失败 -1;
2)send()
int send(int sockfd, const void *msg, size_t len, int flags);
功能:从msg所在的内存中获取长度为len的数据以flags方式写入到sockfd对应的套接字中。
参数:sockfd 如果是服务器则是accept的返回值新fd
如果是客户端则是sockfd的返回值旧fd
msg 要发送的消息
len 要发送的消息长度
flags 消息的发送方式
返回值:成功 发送的字符长度
失败 -1;
ser.c
cs
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <time.h>
typedef struct sockaddr* (SA);
int main(int argc, char *argv[])
{
//监听套接字
int listfd = socket(AF_INET,SOCK_STREAM, 0);
if(-1 == listfd)
{
perror("socket");
exit(1);
}
struct sockaddr_in ser,cli;
bzero(&ser,sizeof(ser));
bzero(&cli,sizeof(cli));
ser.sin_family = AF_INET;
ser.sin_port = htons(50000);
//host to net long
ser.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(listfd,(SA)&ser,sizeof(ser));
if(-1 == ret)
{
perror("bind");
exit(1);
}
//同一时刻三次握手排队数
listen(listfd,3);
socklen_t len = sizeof(cli);
//通信套接字
int conn = accept(listfd,(SA)&cli,&len);
if(-1 == conn)
{
perror("accept");
exit(1);
}
while(1)
{
char buf[512]={0};
int rd_ret = recv(conn,buf,sizeof(buf),0);
if(rd_ret<=0)
{// 0 对方断开连接 -1 错误
break;
}
time_t tm;
time(&tm);
sprintf(buf,"%s %s",buf,ctime(&tm));
send(conn,buf,strlen(buf),0);
}
close(listfd);
close(conn);
return 0;
}
cli.c
cs
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <time.h>
#include <arpa/inet.h>
typedef struct sockaddr* (SA);
int main(int argc, char *argv[])
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == sockfd)
{
perror("socket");
exit(1);
}
struct sockaddr_in ser;
bzero(&ser,sizeof(ser));
ser.sin_family = AF_INET;
ser.sin_port = htons(50000);
//host to net long
ser.sin_addr.s_addr = inet_addr("127.0.0.1");
int ret = connect(sockfd,(SA)&ser,sizeof(ser));
if(-1 == ret)
{
perror("connect");
exit(1);
}
while(1)
{
char buf[512]="hello,this is tcp test";
send(sockfd,buf,strlen(buf),0);
bzero(buf,sizeof(buf));
recv(sockfd,buf,sizeof(buf),0);
printf("buf :%s\n",buf);
sleep(1);
}
close(sockfd);
return 0;
}
tcp发文件,图片------cp 1.png 2.png
ser.c
cs
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
typedef struct sockaddr* (SA);
int main(int argc, char *argv[])
{
//监听套接字
int listfd = socket(AF_INET,SOCK_STREAM, 0);
if(-1 == listfd)
{
perror("socket");
exit(1);
}
struct sockaddr_in ser,cli;
bzero(&ser,sizeof(ser));
bzero(&cli,sizeof(cli));
ser.sin_family = AF_INET;
ser.sin_port = htons(50000);
//host to net long
ser.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(listfd,(SA)&ser,sizeof(ser));
if(-1 == ret)
{
perror("bind");
exit(1);
}
//同一时刻三次握手排队数
listen(listfd,3);
socklen_t len = sizeof(cli);
//通信套接字
int conn = accept(listfd,(SA)&cli,&len);
if(-1 == conn)
{
perror("accept");
exit(1);
}
int fd = open("2.png",O_WRONLY|O_CREAT|O_TRUNC,0666);
if(-1 ==fd)
{
perror("open");
exit(1);
}
while(1)
{
char buf[512]={0};
int rd_ret = recv(conn,buf,sizeof(buf),0);
if(rd_ret<=0)
{// 0 对方断开连接 -1 错误
break;
}
write(fd,buf,rd_ret);
bzero(buf,sizeof(buf));
strcpy(buf,"123");
send(conn,buf,strlen(buf),0);
}
close(fd);
close(listfd);
close(conn);
return 0;
}
cli.c
cs
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <time.h>
#include <arpa/inet.h>
#include <fcntl.h>
typedef struct sockaddr* (SA);
int main(int argc, char *argv[])
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == sockfd)
{
perror("socket");
exit(1);
}
struct sockaddr_in ser;
bzero(&ser,sizeof(ser));
ser.sin_family = AF_INET;
ser.sin_port = htons(50000);
//host to net long
ser.sin_addr.s_addr = inet_addr("127.0.0.1");
int ret = connect(sockfd,(SA)&ser,sizeof(ser));
if(-1 == ret)
{
perror("connect");
exit(1);
}
int fd = open("/home/linux/1.png",O_RDONLY);
if(-1 ==fd)
{
perror("open");
exit(1);
}
while(1)
{
char buf[512]={0};
int rd_ret = read(fd,buf,sizeof(buf));
if(rd_ret<=0)
{
break;
}
send(sockfd,buf,rd_ret,0);
bzero(buf,sizeof(buf));
recv(sockfd,buf,sizeof(buf),0);
}
close(fd);
close(sockfd);
return 0;
}