TCP实现

传输控制协议(TCP,Transmission Control Protocol) 是为了在不可靠的互联网络上提供可靠的端到端字节流而专门设计的一个传输协议。TCP是因特网中的传输层协议,使用三次握手协议建立连接。当主动方发出SYN连接请求后,等待对方回答SYN+ACK,并最终对对方的 SYN 执行 ACK 确认。这种建立连接的方法可以防止产生错误的连接,TCP使用的流量控制协议是可变大小的滑动窗口协议。

1.服务端

基于TCP协议的socket的server端程序编程步骤:

1、建立socket ,使用socket()

2、绑定socket ,使用bind()

3、打开listening socket,使用listen()

4、等待client连接请求,使用accept()

5、收到连接请求,确定连接成功后,使用输入,输出函数recv(),send()与client端互传信息

6、关闭socket,使用close()

服务端代码server.c

`

点击查看代码
/*server.c*/
#include<netinet/in.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h> #define SERVER_PORT 5678 //端口号
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512 int main(int argc, char **argv)
{
// 设置一个socket地址结构server_addr,代表服务器ip地址和端口
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(SERVER_PORT); // 创建用于流协议(TCP)socket,用server_socket代表服务器向客户端提供服务的接口
int server_socket = socket(PF_INET, SOCK_STREAM, 0);
if (server_socket < 0)
{
printf("Create Socket Failed!\n");
exit(1);
}
else
printf("Create Socket Success.\n"); // 把socket和socket地址结构绑定
if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)))
{
printf("Server Bind Port: %d Failed!\n", SERVER_PORT);
exit(1);
}
else
printf("Client Bind Port Success.\n"); // server_socket用于监听
if (listen(server_socket, LENGTH_OF_LISTEN_QUEUE))
{
printf("Server Listen Failed!\n");
exit(1);
}
else
printf("Listening....\n"); // 服务器始终监听
while(1)
{
// 定义客户端的socket地址结构client_addr,当收到来自客户端的请求后,调用accept
// 接受此请求,同时将client端的地址和端口等信息写入client_addr中
struct sockaddr_in client_addr;
socklen_t length = sizeof(client_addr); // 接受一个从client端到达server端的连接请求,将客户端的信息保存在client_addr中
// 如果没有连接请求,则一直等待直到有连接请求为止,这是accept函数的特性
// accpet返回一个新的socket,这个socket用来与此次连接到server的client进行通信
// 这里的new_server_socket代表了这个通信通道
int new_server_socket = accept(server_socket, (struct sockaddr*)&client_addr, &length);
if (new_server_socket < 0)
{
printf("Server Accept Failed!\n");
break;
}
else
printf("Server Accept Success.\n"); char buffer[BUFFER_SIZE];
bzero(buffer, sizeof(buffer));
length = recv(new_server_socket, buffer, BUFFER_SIZE, 0);
if (length < 0)
{
printf("Server Recieve Data Failed!\n");
break;
}
else
printf("Server Recieve Data Success.\n"); char file_name[FILE_NAME_MAX_SIZE + 1];
bzero(file_name, sizeof(file_name));
strncpy(file_name, buffer,
strlen(buffer) > FILE_NAME_MAX_SIZE ? FILE_NAME_MAX_SIZE : strlen(buffer)); FILE *fp = fopen(file_name, "r"); //获取文件操作符
if (fp == NULL)
{
printf("File:\t%s Not Found!\n", file_name);
}
else
{
bzero(buffer, BUFFER_SIZE);
int file_block_length = 0;
while( (file_block_length = fread(buffer, sizeof(char), BUFFER_SIZE, fp)) > 0)
{
// 发送buffer中的字符串到new_server_socket,实际上就是发送给客户端
if (send(new_server_socket, buffer, file_block_length, 0) < 0)
{
printf("Send File:\t%s Failed!\n", file_name);
break;
} bzero(buffer, sizeof(buffer));
}
fclose(fp);
printf("File:\t%s Transfer Finished!\n", file_name);
} close(new_server_socket);
} close(server_socket); return 0;
}

`
2.客户端

基于TCP协议的socket的Client程序编程步骤:

1、建立socket,使用socket()

2、通知server请求连接,使用connect()

3、若连接成功,就使用输入输出函数recv(),send()与server互传信息

4、关闭socket,使用close()

客户端代码client.c

点击查看代码
/*client.c*/
#include<netinet/in.h> // for sockaddr_in
#include<sys/types.h> // for socket
#include<sys/socket.h> // for socket
#include<stdio.h> // for printf
#include<stdlib.h> // for exit
#include<string.h> // for bzero #define SERVER_PORT 5678
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512 int main(int argc, char **argv)
{
if (argc != 2) //判断有没有输入服务器ip
{
printf("Usage: ./%s ServerIPAddress\n", argv[0]);
exit(1);
} // 设置一个socket地址结构client_addr, 代表客户机的ip地址和端口
struct sockaddr_in client_addr;
bzero(&client_addr, sizeof(client_addr));
client_addr.sin_family = AF_INET; // internet协议族IPv4
client_addr.sin_addr.s_addr = htons(INADDR_ANY); // INADDR_ANY表示自动获取本机地址
client_addr.sin_port = htons(0); // auto allocated, 让系统自动分配一个空闲端口 // 创建用于internet的流协议(TCP)类型socket,用client_socket代表客户端socket
int client_socket = socket(AF_INET, SOCK_STREAM, 0);
if (client_socket < 0)
{
printf("Create Socket Failed!\n");
exit(1);
}
else
printf("Create Socket Success.\n"); // 把客户端的socket和客户端的socket地址结构绑定
if (bind(client_socket, (struct sockaddr*)&client_addr, sizeof(client_addr)))
{
printf("Client Bind Port Failed!\n");
exit(1);
}
else
printf("Client Bind Port Success.\n"); // 设置一个socket地址结构server_addr,代表服务器的internet地址和端口
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET; // 服务器的IP地址来自程序的参数
if (inet_aton(argv[1], &server_addr.sin_addr) == 0)
{
printf("Server IP Address Error!\n");
exit(1);
} server_addr.sin_port = htons(SERVER_PORT);
int server_addr_length = sizeof(server_addr); // 向服务器发起连接请求,连接成功后client_socket代表客户端和服务器端的一个socket连接
if (connect(client_socket, (struct sockaddr*)&server_addr, server_addr_length) < 0)
{
printf("Can Not Connect To %s!\n", argv[1]);
exit(1);
}
else
printf("Alreadly Connect To %s.\n", argv[1]); char file_name[FILE_NAME_MAX_SIZE + 1];
bzero(file_name, sizeof(file_name));
printf("Please Input File Name On Server: ");
scanf("%s", file_name); char buffer[BUFFER_SIZE];//缓存区
bzero(buffer, sizeof(buffer));
strncpy(buffer, file_name, strlen(file_name) > BUFFER_SIZE ? BUFFER_SIZE : strlen(file_name));
// 向服务器发送buffer中的数据,此时buffer中存放的是客户端需要接收的文件的名字
send(client_socket, buffer, BUFFER_SIZE, 0);
// send , sendto(), recv(),recvfrom()
FILE *fp = fopen(file_name, "w");
if (fp == NULL)
{
printf("File: %s Can Not Open To Write!\n", file_name);
exit(1);
} // 从服务器端接收数据到buffer中
bzero(buffer, sizeof(buffer));
int length = 0;
while(length = recv(client_socket, buffer, BUFFER_SIZE, 0))
{
if (length < 0)
{
printf("Recieve Data From Server %s Failed!\n", argv[1]);
break;
} int write_length = fwrite(buffer, sizeof(char), length, fp);
if (write_length < length)
{
printf("File:\t%s Write Failed!\n", file_name);
break;
}
bzero(buffer, BUFFER_SIZE);
} printf("Recieve File: %s From Server[%s] Finished!\n", file_name, argv[1]); // 传输完毕,关闭socket
fclose(fp);
close(client_socket);
return 0; }

如图,客户端(左)从服务端(右)下载文件/图片:

二、UDP实现

UDP(User Datagram Protocol) 全称是用户数据报协议,是一种非面向连接的协议,这种协议并不能保证我们的网络程序的连接是可靠的。

1.服务端

基于UDP协议的socket的server编程步骤:

1、建立socket,使用socket()

2、绑定socket,使用bind()

3、以recvfrom()函数接收发送端传来的数据(使用recvfrom函数 时需设置非阻塞,以免程序卡在此处)

4、关闭socket,使用close()

点击查看代码
/*server.c*/
#include<netinet/in.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h> #define SERVER_PORT 5678 //端口号
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512 int main(int argc, char **argv)
{
// 设置一个socket地址结构server_addr,代表服务器internet的地址和端口
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(SERVER_PORT); // create a stream socket
// 创建用于internet的流协议(UDP)socket,用server_socket代表服务器向客户端提供服务的接口
int server_socket = socket(PF_INET, SOCK_DGRAM, 0);
if (server_socket < 0)
{
printf("Create Socket Failed!\n");
exit(1);
}
else
printf("Create Socket Success.\n"); // 把socket和socket地址结构绑定
if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)))
{
printf("Server Bind Port: %d Failed!\n", SERVER_PORT);
exit(1);
}
else
printf("Server Bind Port Success.\n"); printf("Waiting......\n");
// 服务器端一直运行用以持续为客户端提供服务
while(1)
{ // 接受此请求,同时将client端的地址和端口等信息写入client_addr中
struct sockaddr_in client_addr;
int length = 0;
int addrlen = sizeof(client_addr); char buffer[BUFFER_SIZE];
bzero(buffer, sizeof(buffer));
length = recvfrom(server_socket, buffer, BUFFER_SIZE, 0,(struct sockaddr *)&client_addr,&addrlen);
if (length < 0)
{
printf("Server Recieve Data Failed!\n");
break;
} char file_name[FILE_NAME_MAX_SIZE + 1];
bzero(file_name, sizeof(file_name));
strncpy(file_name, buffer,
strlen(buffer) > FILE_NAME_MAX_SIZE ? FILE_NAME_MAX_SIZE : strlen(buffer)); FILE *fp = fopen(file_name, "r");
if (fp == NULL)
{
printf("File:\t%s Not Found!\n", file_name);
}
else
{
bzero(buffer, BUFFER_SIZE);
int file_block_length = 0;
while( (file_block_length = fread(buffer, sizeof(char), BUFFER_SIZE, fp)) > 0)
{
// 发送buffer中的字符串到server_socket,实际上就是发送给客户端
if (sendto(server_socket, buffer, BUFFER_SIZE, 0,(struct sockaddr *)&client_addr,addrlen) < 0)
{
printf("Send File:\t%s Failed!\n", file_name);
break;
} bzero(buffer, sizeof(buffer));
}
fclose(fp);
printf("File:\t%s Transfer Finished!\n", file_name);
}
}
close(server_socket);
return 0;
}

2.客户端

基于UDP协议的socket的client端编程步骤:

1、建立Socket,使socket()

2、用sendto()函数向接收端发送数据。

3、关闭socket,使用close()函数

点击查看代码
/*client.c*/
#include<netinet/in.h> // for sockaddr_in
#include<sys/types.h> // for socket
#include<sys/socket.h> // for socket
#include<stdio.h> // for printf
#include<stdlib.h> // for exit
#include<string.h> // for bzero
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h> #define SERVER_PORT 5678
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512 int main(int argc, char **argv)
{
if (argc != 2)
{
printf("Usage: ./%s ServerIPAddress\n", argv[0]);
exit(1);
} // 设置一个socket地址结构client_addr, 代表客户机的internet地址和端口
struct sockaddr_in client_addr;
bzero(&client_addr, sizeof(client_addr));
client_addr.sin_family = AF_INET; // internet协议族
client_addr.sin_addr.s_addr = htons(INADDR_ANY); // INADDR_ANY表示自动获取本机地址
client_addr.sin_port = htons(0); // auto allocated, 让系统自动分配一个空闲端口 // 创建用于internet的流协议(TCP)类型socket,用client_socket代表客户端socket
int client_socket = socket(AF_INET, SOCK_DGRAM, 0);
if (client_socket < 0)
{
printf("Create Socket Failed!\n");
exit(1);
} // 设置超时,防止recvfrom()函数阻塞
struct timeval timeout;
timeout.tv_sec = 1;//秒
timeout.tv_usec = 0;//微秒
if (setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) == -1) {
perror("setsockopt failed:");
} // 把客户端的socket和客户端的socket地址结构绑定
if (bind(client_socket, (struct sockaddr*)&client_addr, sizeof(client_addr)))
{
printf("Client Bind Port Failed!\n");
exit(1);
} // 设置一个socket地址结构server_addr,代表服务器的internet地址和端口
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET; // 服务器的IP地址来自程序的参数
if (inet_aton(argv[1], &server_addr.sin_addr) == 0)
{
printf("Server IP Address Error!\n");
exit(1);
} server_addr.sin_port = htons(SERVER_PORT);
int server_addr_length = sizeof(server_addr); char file_name[FILE_NAME_MAX_SIZE + 1];
bzero(file_name, sizeof(file_name));
printf("Please Input File Name On Server: ");
scanf("%s", file_name); char buffer[BUFFER_SIZE];
bzero(buffer, sizeof(buffer));
strncpy(buffer, file_name, strlen(file_name) > BUFFER_SIZE ? BUFFER_SIZE : strlen(file_name));
// 向服务器发送buffer中的数据,此时buffer中存放的是客户端需要接收的文件的名字
if( sendto(client_socket, buffer, BUFFER_SIZE, 0,(struct sockaddr *)&server_addr,server_addr_length) )
printf("Waiting receive %s from server....\n",file_name); FILE *fp = fopen(file_name, "w");
if (fp == NULL)
{
printf("File:\t%s Can Not Open To Write!\n", file_name);
exit(1);
} // 从服务器端接收数据到buffer中
bzero(buffer, sizeof(buffer));
int length = 0;
//length = recvfrom(client_socket, buffer, BUFFER_SIZE, 0, (struct sockaddr*)&server_addr, &server_addr_length)//非阻塞
while( length = recvfrom(client_socket, buffer, BUFFER_SIZE, 0, (struct sockaddr*)&server_addr, &server_addr_length))
{
if (length < 0)
{
//printf("Recieve Data From Server %s Failed!\n", argv[1]);
break;
} int write_length = fwrite(buffer, sizeof(char), length, fp);
if (write_length < length)
{
printf("File: %s Write Failed!\n", file_name);
break;
}
bzero(buffer, BUFFER_SIZE);
} printf("Receive File: %s From Server[%s] Finished!\n", file_name, argv[1]); // 传输完毕,关闭socket
fclose(fp);
close(client_socket);
return 0; }

如图,客户端(左)从服务端(右)下载文件/图片:

注:使用recvfrom函数 时需设置非阻塞,以免程序卡住。

Socket通信-Linux系统中C语言实现TCP/UDP图片和文件传输的更多相关文章

  1. 在linux系统中配置NVMe over TCP

    1. 准备环境 1.1 准备linux系统 要求的linux系统可以是运行在物理机上,也可以是虚拟机上: 建议有个linux系统,一个做host,一个做target,如果资源紧张也可以把host和ta ...

  2. Socket 通信原理(Android客户端和服务器以TCP&&UDP方式互通)

    转载地址:http://blog.csdn.net/mad1989/article/details/9147661 ZERO.前言 有关通信原理内容是在网上或百科整理得到,代码部分为本人所写,如果不当 ...

  3. 在linux系统中配置NVMe over FC

    在linux系统中配置NVMe over FC与配置NVMe over TCP类似,前5步操作请参考<在linux系统中配置NVMe over TCP>,网页连接如下: https://w ...

  4. 获得Unix/Linux系统中的IP、MAC地址等信息

    获得Unix/Linux系统中的IP.MAC地址等信息 中高级  |  2010-07-13 16:03  |  分类:①C语言. Unix/Linux. 网络编程 ②手册  |  4,471 次阅读 ...

  5. linux系统中文件的几种类型

    Linux系统是以文件的形式来进行管理的.Linux文件类型常见的有:普通文件.目录.字符设备文件.块设备文件.符号链接文件等,如果想了解这方面知识的弟兄,就进来了解了解. Linux系统不同于win ...

  6. Linux系统中“动态库”和“静态库”那点事儿 /etc/ld.so.conf 动态库的后缀为*.so 静态库的后缀为 libxxx.a ldconfig 目录名

    Linux系统中“动态库”和“静态库”那点事儿 /etc/ld.so.conf  动态库的后缀为*.so  静态库的后缀为 libxxx.a   ldconfig   目录名 转载自:http://b ...

  7. 用户管理 之 Linux 系统中的超级权限的控制

    在Linux操作系统中,root的权限是最高的,也被称为超级权限的拥有者.普通用户无法执行的操作,root用户都能完成,所以也被称之为超级管理用户. 在系统中,每个文件.目录和进程,都归属于某一个用户 ...

  8. Linux系统中“动态库”和“静态库”那点事儿【转】

    转自:http://blog.chinaunix.net/uid-23069658-id-3142046.html 今天我们主要来说说Linux系统下基于动态库(.so)和静态(.a)的程序那些猫腻. ...

  9. Linux系统中“动态库”和“静态库”那点事儿

    摘自http://blog.chinaunix.net/uid-23069658-id-3142046.html 今天我们主要来说说Linux系统下基于动态库(.so)和静态(.a)的程序那些猫腻.在 ...

  10. 为什么在 Linux 系统中,不建议超频

    CPU 是一部计算机内的心脏啦!因为不论你做什么事情都需要 CPU 来加以运作的!(虽然有时工作量大.有时工作量小!),在 586 以前的计算机( 包含 386, 486, 与 586 ) ,CPU ...

随机推荐

  1. trim-all-strings-elements-in-a-complex-object

    package com.xxx.common.util; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.Strin ...

  2. 【网络安全】Linux基础详解

    声明:学习视频来自 b 站 up 主 泷羽 sec,如涉及侵权马上删除文章 声明:本文主要用作技术分享,所有内容仅供参考.任何使用或依赖于本文信息所造成的法律后果均与本人无关.请读者自行判断风险,并遵 ...

  3. Qt编写物联网管理平台48-特色功能设计

    一.前言 在物联网管理平台的实际现场应用过程中,遇到过大大小小几十个改进的需求点,这些需求点都是实际用户提出来的,一方面为了方便用户使用提高用户体验,一方面为了提升整体的整个系统的完整性,甚至有些需求 ...

  4. Qt编写地图综合应用41-在线轮廓图

    一.前言 轮廓图也叫行政区划,这里的轮廓图是指百度地图的区域轮廓图,不是之前文章中提到的echart专用的轮廓图,百度地图的轮廓图就是一个不规则的多边形区域,只不过这个区域的坐标点一般是特别多的,比如 ...

  5. Qt开源作品35-秘钥生成器

    一.前言 在很多商业软件中,需要提供一些可以试运行的版本,这样就需要配套密钥机制来控制,纵观大部分的试用版软件,基本上采用以下几种机制来控制. 远程联网激活,每次启动都联网查看使用时间等,这种方法最完 ...

  6. JMeter JSR223 Sampler 教程:性能测试的魔法棒

    JMeter JSR223 Sampler 教程:性能测试的魔法棒 宝子们,今天咱要深入探索 JMeter 里超厉害的 JSR223 Sampler,它就像是一把万能钥匙,能打开性能测试的各种奇妙大门 ...

  7. NVM及NODE开发环境搭建

    NVM及NODE开发环境搭建 1. 安装NVM 1.1 下载安装包 下载地址 1.2 安装 双击安装包,一路下一步即可.安装完成后在终端输入nvm version,能查到版本号说明安装成功了. 2. ...

  8. Elasticsearch应用介绍

    Elasticsearch 是一个分布式可扩展的实时搜索和分析引擎,一个建立在全文搜索引擎 Apache Lucene(TM) 基础上的搜索引擎.当然 Elasticsearch 并不仅仅是 Luce ...

  9. w3cschool-Scala 教程

    https://www.w3cschool.cn/scala/ Scala 教程关于基础基础知识(续)Finagle 介绍集合Searchbird模式匹配与函数组合类型和多态基础高级类型简单构建工具更 ...

  10. MySQL安装及基本使用教程

      yanzilove win10下安装配置mysql环境 一.下载从https://dev.mysql.com/downloads/mysql/5.1.html#downloads下载zip包,这里 ...