一、前言
互联网概念诞生于20世纪60年代末,从9几年中国接入互联网开始到现在,生活的每个角落都能看到网络的使用。现在物联网时代、共享经济的到来,生活中不仅仅电脑、手机可以接入网络,身边的各个设备也能接入互联网了。 比如:市政路灯、污水井盖、家用电器,汽车等等。
这篇文章介绍在Linux下的socket编程,完成TCP服务器、客户端的创建,实现数据通信。
二、TCP协议介绍
在Linux应用层做编程,接触到是传输层协议,TCP/UDP,如果搞Linux网络驱动开发(网卡驱动),那么底层的网络协议就会接触的更多,协议只是一个数据格式的约定而已,自己也可以设计自己的协议。
下面这张图介绍两个设备通过网络通信的一个大致流程:
TCP协议是点对点传输协议。TCP协议属于C/S模型。
TCP协议里包含服务器和客户端。
服务器必须要比客户端先存在,客户端必须连接服务器,服务器必须被客户端连接。
接下来学习主要学习TCP服务器创建和TCP客户端创建,完成客户端与服务器之间的通信。
TCP服务器可以被多个客户端连接。
Linux下socket编程需要用到的相关函数:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
AF_UNIX, AF_LOCAL Local communication unix(7)
AF_INET IPv4 Internet protocols ip(7)
AF_INET6 IPv6 Internet protocols ipv6(7)
AF_IPX IPX - Novell protocols
AF_NETLINK Kernel user interface device netlink(7)
AF_X25 ITU-T X.25 / ISO-8208 protocol x25(7)
AF_AX25 Amateur radio AX.25 protocol
AF_ATMPVC Access to raw ATM PVCs
AF_APPLETALK AppleTalk ddp(7)
AF_PACKET Low level packet interface packet(7)
AF_ALG Interface to kernel crypto API
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <sys/socket.h>
int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
三、案例代码
3.1 创建TCP服务器
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
/*
TCP服务器创建步骤:
1. 创建socket套接字(类似于open打开文件一样)
2. 绑定端口号和IP地址
3. 设置监听等待队列的数量
4. 等待客户端连接
5. 完成正常数据收发
0x1234
192.168.1.123
255.255.255.255
*/
int main(int argc,char **argv)
{
if(argc!=2)
{
printf("./app <端口号>\n");
return 0;
}
int sockfd;
/*1. 创建socket套接字*/
sockfd=socket(AF_INET,SOCK_STREAM,0);
/*2. 绑定端口号与IP地址*/
struct sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_port=htons(atoi(argv[1])); // 端口号0~65535
addr.sin_addr.s_addr=INADDR_ANY; //inet_addr("0.0.0.0"); //IP地址
if(bind(sockfd,(const struct sockaddr *)&addr,sizeof(struct sockaddr))!=0)
{
printf("服务器:端口号绑定失败.\n");
}
/*3. 设置监听的数量*/
listen(sockfd,20);
/*4. 等待客户端连接*/
int client_fd;
struct sockaddr_in client_addr;
socklen_t addrlen=sizeof(struct sockaddr_in);
client_fd=accept(sockfd, (struct sockaddr *)&client_addr,&addrlen);
if(client_fd<0)
{
printf("客户端连接失败.\n");
return 0;
}
printf("连接的客户端IP地址:%s\n",inet_ntoa(client_addr.sin_addr));
printf("连接的客户端端口号:%d\n",ntohs(client_addr.sin_port));
/*5. 完成通信*/
write(client_fd,"1234567890",10);
/*6. 关闭连接*/
close(client_fd);
close(sockfd);
return 0;
}
3.2 创建TCP客户端
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
/*
TCP客户端创建步骤:
1. 创建socket套接字(类似于open打开文件一样)
2. 连接服务器
3. 完成正常数据收发
*/
int main(int argc,char **argv)
{
if(argc!=3)
{
printf("./app <IP地址> <端口号>\n");
return 0;
}
int sockfd;
/*1. 创建socket套接字*/
sockfd=socket(AF_INET,SOCK_STREAM,0);
/*2. 连接服务器*/
struct sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_port=htons(atoi(argv[2])); // 端口号0~65535
addr.sin_addr.s_addr=inet_addr(argv[1]); //IP地址
if(connect(sockfd,(const struct sockaddr *)&addr,sizeof(struct sockaddr_in))!=0)
{
printf("客户端:服务器连接失败.\n");
return 0;
}
/*3. 完成数据通信*/
char buff[1024];
int cnt;
cnt=read(sockfd,buff,1024);
buff[cnt]='\0';
printf("客户端收到的数据:%s,%d\n",buff,cnt);
close(sockfd);
return 0;
}