前言:
目前同学们对“c语言socket文件传输”大体比较关切,各位老铁们都想要学习一些“c语言socket文件传输”的相关文章。那么小编也在网上汇集了一些有关“c语言socket文件传输””的相关内容,希望姐妹们能喜欢,看官们快快来学习一下吧!1. socket
socket指的是某一主机的 ip地址和端口号
2. socket常见API
创建socket
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
//个人理解:客户端和服务器之间的通信,其实也是进程间的通信,
//但是这是在网络中的,那么进程在网络中发送数据是要知道对方
//的端口号和ip地址才能将数据发送给对方,所以创建socket
//是存进程的ip和端口号
参数
domain: 表示哪一层的网络协议,有ipv4和ipv6等其他选择
type:表示你要以什么形式进程数据传输;例如:面向数据包还是面向字节流
protocol:一般传0,因为前面两个参数已经确定了要将数据发送给谁
绑定端口号
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
//关于绑定(个人理解):
//绑定是为了将服务器的ip和端口号写入创建的socket文件里面,
//创建的socket的文件没有东西,此时将自己的套接字信息写入文件;
//如果没有写套接字信息,系统就会默认分配;此时写入是为了固定
//死套接字信息,告诉所有客户端是一个固定的服务器端口号和ip;
//如果让系统自动分配,那么第二次启动时,服务器的ip和端口号不一致
//就会导致客户端在此连接服务器时,找不到服务器
参数
sockfd:刚才创建的套接字
const struct sockaddr* addr:这是一个结构体的指针,用于服务器自己的套接字信息,这样才能将保证服务器的套接字信息是固定的
len:结构的大小
监听
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
//监听:用于TCP协议进行传输时,服务器需要进行监听,
//因为基于TCP的数据传输是面向连接的,并且是一对多的,
//可能有多个客户端来连接服务器,此时将服务器设定成监听状态,
//谁连接了服务器,服务器就跟谁建立连接,建立连接后,进行数据传输
参数:
sockfd:用于监听的套接字,服务器设置成监听状态,查看有哪个客户端想来连接我
backlog:表示可以连接的客户端个数
接受请求
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//接受请求:用于服务器获取客户端的连接;这里的返回值也是
//一个文件描述符,指向的也是套接字文件,这里用于客户端和
//服务器端之间进行通信;和上面的监听套接字不一样,监听状态
//要一直存在,查看有没有客户端来连接我
参数
sockfd:监听套接字,这是一个媒介,当客户端来了,创建一个套接字存自己和客户的信息,让监听套接字继续监听
结构体指针:这里的结构体存放的是客户端的ip和端口号;这是给程序员看的,其实也就是给人看的,如果你想知道客户端的ip和端口号,就接受,如果你不关心,可以写NULL
结构体大小的指针:这里是一个传出传入型参数,将客户端的ip和端口号存入,必定要知道大小
收数据
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
//由于TCP是面向连接的,前面也已经知道我连的是哪个客户端了,
//在这里可以直接进行通信,进行收数据和发数据
参数:
sockfd:刚才建立连接时创建的socket文件描述符
buf:你接受的数据存放的缓冲区
len:你期望读多少数据
flags:0表示阻塞式接收数据,非0表示非阻塞时收数据`
发数据
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
//和收数据是相对的,这里不在解释
建立连接
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
//这里的连接指的是客户端主动去连接服务器,因为服务器只有一个,
//客户端有多个,客户端要主动去连服务器才可以建立连接
参数:
sockfd:和服务器创建socket文件的作用是一样的,不在多做解释
存ip地址和端口号:既然我要去连接服务器,就要知道连接的哪个服务器,不能乱连
结构体长度:ip和端口号存在结构体中,将结构体的首地址传过去,必定要知道大小
3. TCP协议的传输特点
面向连接:服务器一旦和客户端建立连接,就需要为此分配资源,建立连接关系,当断开连接时,需要释放资源
面向字节流:以字节来读取和写入,字节数的大小完全取决于自己
可靠传输:由于服务器已经和客户端建立了通信,就会保证数据能够传输成功,不会存在丢数据的现象
4. 客户端和服务器传输流程图5. 基于多线程的客户端服务器传输
服务器端:
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
pthread_t tid;
void* ProcessWorker(void* arg)
{
int fd = *(int*)arg;
char buf[128];
while(1){//不断从客户端拿数据,在发回给客户端
ssize_t s = read(fd, buf, sizeof(buf));
if(s < 0){
perror("read");
break;
}
else if(s == 0){
printf("client quit...\n");
break;
}
buf[s] = 0;
printf("client# %s\n",buf);
send(fd, buf, strlen(buf), 0);
}
close(fd);
}
// ./server ip port
int main(int argc, char* argv[])
{
if(argc != 3){
printf("Usage ./server [ip] [port]\n");
return 1;
}
//创建套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0){
perror("socket");
return 2;
}
//绑定端口号
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(argv[1]);
server.sin_port = htons(atoi(argv[2]));
if(bind(sockfd, (struct sockaddr*)&server, sizeof(server)) < 0){//绑定失败
perror("bind");
return 3;
}
//监听
if(listen(sockfd, 5) < 0){
perror("listen");
return 4;
}
struct sockaddr_in client;//用于接收到客户端的ip和端口号
socklen_t len = sizeof(client);
char buf[128];
for(;;){//服务器一直运行
int clientfd = accept(sockfd, (struct sockaddr*)&client, &len);
if(clientfd < 0){//当没有接收到客户端,尝试重新接收
perror("accept");
continue;
}
printf("Get connet [%s] [%d]\n",inet_ntoa(client.sin_addr), ntohs(client.sin_port));
//创建线程,主线程去监听,新线程去处理
pthread_create(&tid, NULL, ProcessWorker, (void*)&clientfd);
//在这里不能关闭文件描述符,因为主线程和新线程看到的是一个文件描述符,当把文件描述符关闭后,新线程无法获取从客户端发送的请求或消息
pthread_detach(tid);//并将新线程分离出去
}
return 0;
}
服务器端:
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
// ./client ip地址 端口号
int main(int argc,char* argv[])
{
//进程 ip地址 端口号
if(argc != 3){
perror("Usage ./server [ip] [port]\n");
return 1;
}
//ipv4 面向字节流 创建socket
int sock = socket(AF_INET, SOCK_STREAM,0);
if(sock < 0){
perror("socket");
return 2;
}
struct sockaddr_in server;//绑定的是服务器的ip和端口号
server.sin_family = AF_INET;//协议族
server.sin_addr.s_addr = inet_addr(argv[1]);//将ip专程4字节ip地址,在转成大端字节序
server.sin_port = htons(atoi(argv[2]));
//连接服务器
int ret = connect(sock,(struct sockaddr*)&server,sizeof(server));
if(ret < 0){//连接失败
perror("connect");
return 3;
}
//表示连接成功
printf("Connect success...\n");
char buf[1024];
while(1){
printf("client: ");
fflush(stdout);
ssize_t s = read(0, buf, sizeof(buf)-1);
if(s > 0){//读取数据
buf[s-1] = 0;
write(sock, buf, strlen(buf));
}
else{
break;
}
ssize_t rd = read(sock, buf, sizeof(buf)-1);
if(rd > 0){
buf[rd] = 0;
printf("server# %s\n",buf);
}
}
close(sock);
return 0;
}
6. 基于多进程的客户端服务器传输
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
// ./server ip port
int main(int argc, char* argv[])
{
if(argc != 3){
printf("Usage ./server [ip] [port]\n");
return 1;
}
//创建套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0){
perror("socket");
return 2;
}
//绑定端口号
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(argv[1]);
server.sin_port = htons(atoi(argv[2]));
if(bind(sockfd, (struct sockaddr*)&server, sizeof(server)) < 0){//绑定失败
perror("bind");
return 3;
}
//监听
if(listen(sockfd, 5) < 0){
perror("listen");
return 4;
}
struct sockaddr_in client;//用于接收到客户端的ip和端口号
socklen_t len = sizeof(client);
char buf[128];
for(;;){//服务器一直运行
int clientfd = accept(sockfd, (struct sockaddr*)&client, &len);
if(clientfd < 0){//当没有接收到客户端,尝试重新接受
perror("accept");
continue;
}
printf("Get connet [%s] [%d]\n",inet_ntoa(client.sin_addr), ntohs(client.sin_port));
pid_t pid = fork();
if(pid == 0){//子进程创建孙子进程,然后退出
if( fork() == 0){//创建的子进程,去处理客户端发送过来的消息
//1.从客户端接受消息,在将其发送回去
while(1){//子进程不断从客户端读数据,在将其发回去
ssize_t s = recv(clientfd, buf, sizeof(buf)-1, 0);
if(s > 0){
buf[s] = 0;
printf("client# %s\n",buf);
ssize_t ret = send(clientfd, buf, strlen(buf), 0);
if(ret < 0){
perror("send");
return 1;
}
}
else if(s == 0){//客户端退出
printf("client quit...\n");
break;
}
else{
break;
}
}
exit(0);//自己退出
}
else if(pid > 0){//回收子进程,继续监听有没有客户端
waitpid(pid, NULL, 0);
close(clientfd);
}
}
}
return 0;
}
更多linux免费视频资料获取 后台私信【架构】
标签: #c语言socket文件传输