Linux C语言实现socket服务器和客户端
技术:Linux、C语言
概述
Demo在Linux系统中,用C语言实现socket服务器和客户端,实现过程涉及到的知识点有:tcp通信、socket通信和线程等。
详细
一、Socket通信:
1. 含义:
Socket 是在应用层和传输层之间的一个抽象层,它把 TCP/IP 层复杂的操作抽象为几个简单的接口,供应用层调用实现进程在网络中的通信。
2. 通信流程:
3. Socket通信部分接口说明:
1. socket() 功 能:创建套接字 原 型:int socket(int domain, int type, int protocol); 参 数: domain:协议族,通常为AF_INET,表示TCP/IP协议 type:socket类型,如:SOCK_STREAM(指TCP)和SOCK_DGRAM(指UDP)等等 protocol:套接口所用的协议,一般为0 返回值: 成功:socket文件描述符 失败:-1,并设置errno 2. bind() 功 能:将套接字和指定的端口相连 原 型:int bind(int sock_fd, struct sockaddr_in *my_addr, int addrlen); 参 数: sock_fd:socket文件描述符 my_addr:设置服务器信息的sockaddr_in结构体指针 addrlen:sockaddr_in结构体的长度 返回值: 成功:0 失败:-1,并设置errno 说 明: struct sockaddr_in{ short int sin_family; //网络通信网络层协议 AF_INET unsigned short int sin_port; //端口 struct in_addr sin_addr; //IP地址 unsigned char sin_zero[8]; //让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节 }; 3. connect() 功 能:连接服务器请求(客户端使用) 原 型:int connect(int sock_fd, struct sockaddr *serv_addr,int addrlen); 参 数: sock_fd:socket文件描述符 serv_addr:包含远端主机IP地址和端口号的指针 addrlen:sockaddr_in结构体的长度 返回值: 成功:0 失败:-1,并设置errno 4. listen() 功 能:创建一个套接口并监听申请的连接 原 型:int listen(int sock_fd, int backlog); 参 数: sock_fd:socket文件描述符 backlog:请求队列中允许的最大请求数 返回值: 成功:0 失败:-1,并设置errno 5. accecpt() 功 能:接受客户端的服务请求 原 型:int accept(int sock_fd, struct sockadd_in* addr, int addrlen); 参 数: sock_fd:被监听的socket文件描述符 addr:包含客户端IP地址和端口号的指针 addrlen:sockaddr_in结构体的长度 返回值: 成功:客户端套接字描述符 失败:-1,并设置errno 6. write() 功 能:写入数据到fd中 原 型:ssize_t write(int fd,const void *buf,size_t nbytes); 参 数: fd:socket文件描述符 buf:字符串数据地址 nbytes:字符串数据大小 返回值: 实际写入的字节数,小于0为写入错误 6、read() 功 能:从fd中读取数据 原 型:ssize_t read(int fd,void *buf,size_t nbyte) 参 数: fd:socket文件描述符 buf:字符串数据地址 nbyte:字符串数据大小 返回值: >0: 实际读取的大小 =0:读到末尾了 <0:读取错误 8、close() 功 能:关闭套接字 原 型:int close(sock_fd); 参 数: sock_fd:要关闭的socket文件描述符 返回值: 成功:0 失败:-1
二、线程部分接口说明:
注意:Linux系统中使用线程库,编译时要加-lpthread,例如:gcc server.c -o server -lpthread 1. pthread_create() 功 能:创建线程 原 型:int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); 参 数: thread:线程的TID号,唯一的 attr:线程的属性 start_routine:任务函数指针,指向的函数类型 : void *func(void *) arg:传递给任务函数使用的参数 返回值: 成功:0 失败:错误编号 2. pthread_exit() 功 能:终止调用它的线程并返回一个指向某个对象的指针(常与pthread_join()一起使用) 原 型:void pthread_exit(void *retval); 参 数: retval:线程的退出状态值 返回值: 无 3. pthread_join() 功 能:以阻塞的方式等待指定的线程结束 原 型:int pthread_join(pthread_t thread, void **retval); 参 数: thread:等待的线程的TID号 retval:用户定义的指针,用来存储被等待线程的返回值 返回值: 成功:0 失败:错误编号 4. pthread_cancel() 功 能:线程的取消 原 型:int pthread_cancel(pthread_t thread); 参 数: thread:取消的线程的TID号 返回值: 成功:0 失败:错误编号
三、部分代码
int main() { //1.创建网络的通信对象 socket_fd = socket(AF_INET,SOCK_STREAM,0); if(socket_fd < 0) { perror("socket error!"); return -1; } //2.定义服务器注册的网络端口 和 网络 IP 结构体 struct sockaddr_in server_addr,client_addr; int len = sizeof(client_addr); server_addr.sin_family = AF_INET; //设置网络层协议 server_addr.sin_port = htons(6666); //设置端口号 server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //设置IP地址 //3.绑定服务器的IP地址 int ret = bind(socket_fd,(struct sockaddr *)&server_addr,sizeof(server_addr)); if(ret != 0) { perror("bind error!"); return -1; } //4.把服务器socket,设置为监听模式 ret = listen(socket_fd,5); if(ret != 0) { perror("listen error!"); return -1; } printf("等待客户端的连接请求:\n"); //5.接收客户端的连接请求 client_fd = accept(socket_fd,(struct sockaddr *)&client_addr,&len); if(client_fd < 0) { perror("socket error!"); return -1; } printf("ip:%s\n",inet_ntoa(client_addr.sin_addr)); printf("port:%d\n",ntohs(client_addr.sin_port)); //创建线程 pthread_t tid; pthread_create(&tid,NULL,sock_read,NULL); pthread_detach(tid); //设置为分离属性 //5.发送网络数据 char buf[1024] = {0}; while(1) { scanf("%s",buf); write(client_fd,buf,strlen(buf)); } close(socket_fd); return 0; }
运行命令:./server和./client
四、实现效果
五、总结
后续跟新以下Demo:
六、项目结构图
本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
手机上随时阅读、收藏该文章 ?请扫下方二维码