实验代码参考文章链接:
TCP通讯:https://blog.youkuaiyun.com/lihao21/article/details/64624796
UDP通讯:https://www.it610.com/article/1279896532153286656.html
TCP传输图片:http://www.voidcn.com/article/p-bvpkuxmc-dc.html
实例:Linux下使用C语言编程实现TCP/UDP协议下服务端和客户端的通讯,完成大小写转换
TCP服务端
#include <sys/socket.h>//该头文件包含了多种socket编程所需要的函数定义
#include <stdlib.h>//该头文件包含了c语言常用的系统函数:杂项函数及内存分配函数,如malloc(),free(),system(),exit(),atoi(),rand()等等
#include <stdio.h>//标准输入输出头文件
#include <string.h>//字符串处理头文件,如strlen(),strcat(),strcpy(),strcmp()
#include <netinet/in.h>//互联网地址簇头文件,包括socketaddr_in结构体,htons系统调用等
#include <arpa/inet.h>//提供ip地址转换函数
#include <unistd.h>//用于Linux/unix系统调用,包含read(),write(),getpid()等函数
int main(int argc, char * argv[])
{
//创建套接字
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0)
{
//perror()用来将上一个函数发生错误的原因输出到标准设备(stderr)。参数 s 所指的字符串会先打印出,后面再加上错误原因字符串。
perror("cannot create socket");
return 0;
}
printf("created socket, server_fd: %d\n", server_fd);
//命名套接字,设置套接字属性(将该套接字关联一个ip地址和端口号)
struct sockaddr_in server_addr;//服务端套接字地址
memset((void*)&server_addr, 0, sizeof(server_addr));//初始化套接字地址结构
server_addr.sin_family = AF_INET;//协议类型,IPv4或者IPv6
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//转换成网络字节顺序,不同体系结构的机器之间无法通信,要转换成一种约定的数序,转换过来就是0.0.0.0,泛指本机的意思,也就是表示本机的所有IP,一个机器可能有多个ip地址,若只设置一个ip地址作为套接字的ip地址,则其他机器只能与本机的这个ip地址通讯
server_addr.sin_port = htons(6240);//端口号
//绑定ip地址、端口等信息到socket上
if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
//bind系统调用把第二个参数中的地址分配给与文件描述符socket关联的套接字地址
{
perror("bind failed");
return 0;
}
printf("bind complete, port number:%d\n", ntohs(server_addr.sin_port));//ntohs函数将一个16位数由网络字节顺序转换为主机字节顺序
//创建套接字队列,开启监听
if (listen(server_fd, 5) < 0)
{
perror("listen failed");
return 0;
}
printf("socket listen, server_fd:%d\n", server_fd);
const int MAXBUF = 256;//最大传输字节数
char buffer[MAXBUF];//定义接收数据的缓冲区
struct sockaddr_in client_addr;//客户端套接字地址
int client_addr_len = sizeof(client_addr);
int client_fd;//客户端文件描述符
//执行accept函数,服务端阻塞,等待接收客户端上来的连接请求
printf("waiting for connect ......\n");
client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_addr_len);
if(client_fd<0)
{
printf("accept failed!");
return -1;
}
printf("accept client, client fd:%d, ip:%s, port:%d\n",
client_fd, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));//这里的inet_ntoa是将网络地址转换成“.”点隔的字符串格式的函数
//收发数据
printf("waiting for data ......\n");
while (1)
{
//这里不需要做循环也可以,只是需要完成客户端发送过来一个字符串,服务端处理后返回客户端处理后的结果
//从客户端读取到数据(即字符串),存放在buffer数组中
int nbytes = read(client_fd, buffer, MAXBUF);
if(nbytes < 0)
{
printf("read data failed!\n");
return -1;
}
printf("read from client, bytes: %d, data: %s\n", nbytes, buffer);
//大小写转换
for(int i = 0; i < sizeof(buffer); i++)
{
if(buffer[i] >= 'A' && buffer[i] <= 'Z')
buffer[i] = buffer[i] + 32;
else if(buffer[i] >= 'a' && buffer[i] <= 'z')
buffer[i] = buffer[i] - 32;
}
//发送数据给客户端
nbytes = write(client_fd, buffer, sizeof(buffer));
if(nbytes < 0)
{
printf("write data failed!\n");
return -1;
}
printf("write to client, bytes: %d, data: %s\n", nbytes, buffer);
break;
}
printf("The data received!\n");
//关闭套接字
close(client_fd);
return 0;
}
TCP客户端
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char * argv[])
{
//创建套接字
int client_fd = socket(AF_INET, SOCK_STREAM, 0);
if (client_fd < 0)
{
perror("cannot create socket");
return 0;
}
printf("created socket, client_fd :%d\n", client_fd);
//命名套接字,设置套接字属性,客户端由内核选择ip地址和端口
//由于服务端已bind()绑定了ip地址和端口号,正在等待连接,则客户端无需绑定ip地址和端口号,客户端会在发送给服务端的数据中包含自身系统随机分配的端口和客户端的ip地址
struct sockaddr_in client_addr;
memset((char*)&client_addr, 0, sizeof(client_addr));
client_addr.sin_family = AF_INET;
client_addr.sin_addr.s_addr = htonl(INADDR_ANY);
client_addr.sin_port = htons(0);
//绑定ip地址、端口等信息到socket上
if (bind(client_fd, (struct sockaddr*)&client_addr, sizeof(client_addr)) < 0)
{
perror("bind failed");
return 0;
}
//设置要连接的对方的ip地址和端口等属性
const char* server = "127.0.0.1";//服务端ip
struct sockaddr_in server_addr;
memset((char*)&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
inet_aton(server, &server_addr.sin_addr);
server_addr.sin_port = htons(6240);
//请求连接服务器
int result = connect(client_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
if (result < 0)
{
perror("connect failed\n");
}
else
printf("connected!\n");
const int MAXBUF = 256;//最大传输字节数
char buffer_read[MAXBUF];//用来存放从服务端接收到的数据
char buffer_write[]="SjhDtcP";//将要传输给服务端的数据
while(1)
{
//传输数据给服务端
int nbytes = write(client_fd, buffer_write, sizeof(buffer_write));
printf("write to server, bytes: %d, data: %s\n", nbytes, buffer_write);
//从服务端接收数据
nbytes = read(client_fd, buffer_read, MAXBUF);
printf("read from server, bytes: %ld, data: %s\n", sizeof(buffer_read), buffer_read);
break;
}
//关闭套接字
close(client_fd);
return 0;
}
UDP服务端
#include <sys/socket.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char * argv[])
{
//创建套接字
int server_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (server_fd < 0)
{
perror("cannot create socket");
return 0;
}
printf("created socket, server_fd: %d\n", server_fd);
//命名套接字,设置socket属性(将该套接字关联一个ip地址和端口号)
struct sockaddr_in server_addr;//套接字地址
memset((void*)&server_addr, 0, sizeof(server_addr));//初始化套接字地址结构
server_addr.sin_family = AF_INET;//协议类型,IPv4或者IPv6
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//ip地址
server_addr.sin_port = htons(6240);//端口号
if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
//bind系统调用把参数address中的地址分配给与文件描述符socket关联的套接字地址
{
perror("bind failed");
return 0;
}
printf("bind complete, port number:%d\n", ntohs(server_addr.sin_port));
printf("waiting for data ......\n");
//定义客户端地址和地址长度
struct sockaddr_in client_addr;
int client_addr_len = sizeof(client_addr);
const int MAXBUF = 256;
char buffer[MAXBUF];
while (1)
{
//接收数据,由于接下来还需要向来源端发送数据,则将获取到的客户端的ip地址和端口号存储起来
int nbytes = recvfrom(server_fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&client_addr, &client_addr_len);
if(nbytes < 0)
{
printf("read data failed!\n");
return (-1);
}
printf("read from client, bytes: %d, data: %s\n", nbytes, buffer);
for(int i = 0; i < sizeof(buffer); i++)
{
if(buffer[i] >= 'A' && buffer[i] <= 'Z')
buffer[i] = buffer[i] + 32;
else if(buffer[i] >= 'a' && buffer[i] <= 'z')
buffer[i] = buffer[i] - 32;
}
//发送数据,指定客户端的ip地址和端口号
nbytes = sendto(server_fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&client_addr, client_addr_len);
if(nbytes < 0)
{
printf("write data failed!\n");
return (-1);
}
printf("write to client, bytes: %d, data: %s\n", nbytes, buffer);
break;
}
//关闭套接字
close(server_fd);
return 0;
}
UDP客户端
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char * argv[])
{
//创建套接字
int client_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (client_fd < 0)
{
perror("cannot create socket");
return 0;
}
printf("created socket, client_fd :%d\n", client_fd);
//命名套接字,设置套接字属性
struct sockaddr_in server_addr;
memset((char*)&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");//客户端指定了服务端的ip地址
server_addr.sin_port = htons(6240);//服务端端口号
const int MAXBUF = 256;
char buffer_read[MAXBUF];
char buffer_write[]="SjhDtcP";
while(1)
{
//发送数据,指定了发送的服务端的ip地址和端口号,每一次发送数据都要指定
int nbytes = sendto(client_fd, buffer_write, sizeof(buffer_write), 0, (struct sockaddr*)&server_addr, sizeof(server_addr));
if(nbytes < 0)
{
printf("write data failed!");
return -1;
}
printf("write to server, bytes: %d, data: %s\n", nbytes, buffer_write);
//接收数据,由于不需要再次向来源服务端进行通信,因此无需记录数据来源服务端的地址信息和端口信息
nbytes = recvfrom(client_fd, buffer_read, sizeof(buffer_read), 0, NULL, NULL);
if(nbytes < 0)
{
printf("read data failed!");
return -1;
}
printf("read from server, bytes: %d, data: %s\n", nbytes, buffer_read);
break;
}
//关闭套接字
close(client_fd);
return 0;
}
实例:Linux下实现使用C语言编程实现TCP/UDP协议下服务端和客户端的通讯,完成图片的传输
TCP服务端
#include <sys/socket.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char * argv[])
{
//创建套接字
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0)
{
perror("cannot create socket");
return 0;
}
printf("created socket, server_fd: %d\n", server_fd);
//命名套接字(将该套接字关联一个ip地址和端口号)
struct sockaddr_in server_addr;//套接字地址
memset((void*)&server_addr, 0, sizeof(server_addr));//初始化套接字地址结构
server_addr.sin_family = AF_INET;//协议类型,IPv4或者IPv6
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//ip地址
server_addr.sin_port = htons(6240);//端口号
if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
//bind系统调用把第二个参数中的地址分配给与文件描述符socket关联的套接字地址,即绑定
{
perror("bind failed");
return 0;
}
printf("bind complete, port number:%d\n", ntohs(server_addr.sin_port));
//创建套接字队列
if (listen(server_fd, 5) < 0)
{
perror("listen failed");
return 0;
}
printf("socket listen, server_fd:%d\n", server_fd);
struct sockaddr_in client_addr;
int client_addr_len = sizeof(client_addr);
int client_fd;
struct Data//接收数据的数据结构
{
int number;
int length;
char receivemessage[1024];
int fin;//标志位,标志数据是否传输完毕
}data;
FILE * fp;
fp = fopen("/home/the-good/Desktop/1.jpg", "w+");//w+表示新建一个文本文件,允许读写
if(fp==NULL)
{
printf("open failed!\n");
return -1;
}
//服务器等待客户连接
client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_addr_len);
if(client_fd<0)
{
printf("accept failed!");
return -1;
}
printf("accept client, client fd:%d, ip:%s, port:%d\n",
client_fd, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
printf("waiting for data ......\n");
while (1)
{
//读取数据
memset((char *)&data.receivemessage, '0', sizeof(struct Data));
int nbytes = read(client_fd, (char *)&data, sizeof(struct Data));
if(nbytes < 0)
{
printf("read data failed!\n");
return (-1);
}
printf("read from client, bytes: %d, data: %s\n", nbytes, data.receivemessage);
fwrite(data.receivemessage, data.length, 1, fp);//将读取到的数据写入新建的1.jpg中
if(data.fin == 0)//若data.fin=0,说明数据包还没传完,具体看客户端
continue;
else
break;
}
printf("The data received!\n");
//关闭套接字
close(client_fd);
return 0;
}
TCP客户端
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char * argv[])
{
//创建套接字
int client_fd = socket(AF_INET, SOCK_STREAM, 0);
if (client_fd < 0)
{
perror("cannot create socket");
return 0;
}
printf("created socket, client_fd :%d\n", client_fd);
//命名套接字,客户端由内核选择ip地址和端口
struct sockaddr_in client_addr;
memset((char*)&client_addr, 0, sizeof(client_addr));
client_addr.sin_family = AF_INET;
client_addr.sin_addr.s_addr = htonl(INADDR_ANY);
client_addr.sin_port = htons(0);
if (bind(client_fd, (struct sockaddr*)&client_addr, sizeof(client_addr)) < 0)
{
perror("bind failed");
return 0;
}
//构造服务器的地址
const char* server = "127.0.0.1";//服务器ip
struct sockaddr_in server_addr;
memset((char*)&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
inet_aton(server, &server_addr.sin_addr);
server_addr.sin_port = htons(6240);
//请求连接服务器
int result = connect(client_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
if (result < 0)
{
perror("connect failed\n");
}
else
printf("connected!\n");
//读取数据的数据结构
struct Data
{
int number;
int length;
char sendMessage[1024];
int fin;
}data;
FILE * fp;
fp=fopen("//home//the-good//Desktop//picture.jpg", "rb");//这里的rb表示打开一个二进制文件,文件必须存在,只允许读
if(fp==NULL)
{
printf("open failed!\n");
return (-1);
}
printf("opened!\n");
fseek(fp, 0, SEEK_END);//将文件指针移动到文件末尾位置
int end = ftell(fp);//记录文件大小
fseek(fp, 0, 0);//将文件指针返回文件开始位置
while(end>0)
{
memset((char *)data.sendMessage, '0', sizeof(data.sendMessage));
fread(data.sendMessage, 1024, 1, fp);
if(end >=1024)//分包发送,一次只传1024字节数据
{
//说明数据大于1024字节,发送了一次数据后还有数据未发完,因此data.fin=0
data.fin = 0;
data.length = 1024;
}
else
{
//说明未传的数据已经小于1024字节,在下面的一次数据传输过程中即可完成所有数据的传输,因此置data.fin=1
data.fin = 1;
data.length = end;
}
int nbytes = write(client_fd, (char *)&data, sizeof(struct Data));//发送整个结构体
if(nbytes < 0)
{
printf("send() failed!");
return -1;
}
else
end -= 1024;
}
//关闭套接字
close(client_fd);
return 0;
}
UDP服务端
#include <sys/socket.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char * argv[])
{
//创建套接字
int server_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (server_fd < 0)
{
perror("cannot create socket");
return 0;
}
printf("created socket, server_fd: %d\n", server_fd);
//命名套接字(将该套接字关联一个ip地址和端口号)
struct sockaddr_in server_addr;//套接字地址
memset((void*)&server_addr, 0, sizeof(server_addr));//初始化套接字地址结构
server_addr.sin_family = AF_INET;//协议类型,IPv4或者IPv6
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//ip地址
server_addr.sin_port = htons(6240);//端口号
if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)//bind系统调用把参数address中的地址分配给与文件描述符socket关联的套接字地址
{
perror("bind failed");
return 0;
}
printf("bind complete, port number:%d\n", ntohs(server_addr.sin_port));
printf("waiting for data ......\n");
struct sockaddr_in client_addr;
int client_addr_len = sizeof(client_addr);
struct Data//接收数据的数据结构
{
int number;
int length;
char receivemessage[2048];
int fin;
}data;
FILE * fp;
fp = fopen("//home//the-good//Desktop//TCP-UDP-socket//UDP.jpg", "w+");
if(fp==NULL)
{
printf("open failed!\n");
return -1;
}
while (1)
{
//读取数据
memset((char *)&data.receivemessage, '0', sizeof(struct Data));
int nbytes = recvfrom(server_fd, (char *)&data, sizeof(struct Data), 0, (struct sockaddr*)&client_addr, &client_addr_len);
if(nbytes < 0)
{
printf("read data failed!\n");
return (-1);
}
printf("read from client, bytes: %d, data: %s\n", nbytes, data.receivemessage);
fwrite(data.receivemessage, data.length, 1, fp);//将读取到的数据写入新建的UDP.jpg中
if(data.fin == 0)//若data.fin=0,说明数据包还没传完
continue;
else
break;
}
//关闭套接字
close(server_fd);
return 0;
}
UDP客户端
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char * argv[])
{
//创建套接字
int client_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (client_fd < 0)
{
perror("cannot create socket");
return 0;
}
printf("created socket, client_fd :%d\n", client_fd);
//初始化定义
struct sockaddr_in server_addr;
memset((char*)&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_port = htons(6240);
//读取数据的数据结构
struct Data
{
int number;
int length;
char sendMessage[2048];
int fin;
}data;
FILE * fp;
fp=fopen("//home//the-good//Desktop//TCP-UDP-socket//picture.jpg", "rb");
if(fp==NULL)
{
printf("open failed!\n");
return (-1);
}
printf("opened!\n");
fseek(fp, 0, SEEK_END);//将文件指针移动到文件末尾位置
int end = ftell(fp);//记录文件大小
fseek(fp, 0, 0);//文件指针返回文件开始位置
while(end>0)
{
memset((char *)data.sendMessage, '0', sizeof(data.sendMessage));
fread(data.sendMessage, 2048, 1, fp);
if(end >=2048)//分包发送,一次只传2048字节数据
{
data.fin = 0;
data.length = 2048;
}
else
{
data.fin = 1;
data.length = end;
}
int nbytes = sendto(client_fd, (char *)&data, sizeof(struct Data), 0, (struct sockaddr*)&server_addr, sizeof(server_addr));//发送整个结构体
if(nbytes < 0)
{
printf("send() failed!");
return -1;
}
else
end -= 2048;
}
//关闭套接字
close(client_fd);
return 0;
}