Linux网络编程8——对TCP与UDP的简易封装
引言
每次使用socket通信,都会有很对相似的操作。本文,会对TCP与UDP通信做一简单封装,并生成动态库。
代码
my_socket.h
#ifndef __MY_SOCKET_H__
#define __MY_SOCKET_H__ #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define IN
#define OUT
#define IN_OUT
#define MY_TCP 1
#define MY_UDP 2
typedef struct sockaddr* pSA ;
typedef struct sockaddr_in SA ;
#define MY_ASSERT(flag,msg) ( (flag) ? NULL : ( fprintf(stdout,msg), exit(EXIT_FAILURE) ) ) // NULL代表什么也不做 void my_socket(OUT int *local_sfd, int protocal, char *local_ip, int local_port);
void my_listen(int local_sfd, int backlog);
void my_accept(OUT int *peer_sfd, int local_sfd, OUT pSA peer_addr, IN_OUT int *addr_len );
void my_connect(int local_sfd, pSA peer_addr, int addr_len);
void my_recv(OUT int *recv_len, int peer_sfd, IN_OUT void *base, int len);
void my_send(OUT int *send_len, int peer_sfd, void *base, int len);
void my_recvfrom(OUT int *recvfrom_len, int peer_sfd, IN_OUT void *base, int len, OUT pSA peer_addr, IN_OUT int *addr_len);
void my_sendto(OUT int *sendto_len, int peer_sfd, OUT void *base, int len, pSA peer_addr, int addr_len);
void my_close(int sfd); #endif
my_socket.c
/*************************************************************************
> File Name: my_socket.c
> Author: KrisChou
> Mail:zhoujx0219@163.com
> Created Time: Mon 01 Sep 2014 06:54:48 PM CST
************************************************************************/ /* 本代码用于在一台主机上模拟socket通信。因此IP地址对于server和client而言是一样的。
* 为了简化代码,此处即使是客户端,也提前分配好端口号。事实上,主动方的端口号可以由系统分配,不用提前绑定
* --> 无论server或者client,都会预先绑定本地socket */ /* 本代码local_sfd代表本地socket描述符。
* 对于服务器而言,就是用于监听的socket; 对于客户端而言就是用于通信的socket
* peer_sfd,代表与对方通信的socket描述符。
* 对于服务器而言,由accept以传出参数形式返回;对于客户端而言,就是本地socket */ #include "my_socket.h" void my_socket(OUT int *local_sfd, int protocal, char *local_ip, int local_port)
{
MY_ASSERT(protocal == MY_TCP || protocal == MY_UDP, "wrong arg! protocal is MY_TCP or MY_UDP! \n");
/* 创建本地socket */
if(protocal == MY_TCP)
{
MY_ASSERT(-1 != (*local_sfd = socket(AF_INET, SOCK_STREAM, 0)), "tcp_socket init falure!\n");
}else if(protocal == MY_UDP)
{
MY_ASSERT(-1 != (*local_sfd = socket(AF_INET, SOCK_DGRAM, 0)), "udp_socket init failure!\n");
}
/* 将本地联系方式bind到本地socket */
SA local_addr;
memset(&local_addr, 0, sizeof(SA));
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(local_port);
local_addr.sin_addr.s_addr = inet_addr(local_ip);
MY_ASSERT( 0 == bind(*local_sfd, (pSA)&local_addr, sizeof(SA)), "bind failure!\n");
} /*----------------------------- 以下针对TCP ----------------------------------------------------- */ /* server: listen + accept */
void my_listen(int local_sfd, int backlog)
{
MY_ASSERT( 0 == listen(local_sfd, backlog), "listen failure!\n");
} void my_accept(OUT int *peer_sfd, int local_sfd, OUT pSA peer_addr, IN_OUT int *addr_len )
{
MY_ASSERT(-1 != (*peer_sfd = accept(local_sfd, peer_addr, addr_len)), "accept failure!\n");
} /* client: connect */
void my_connect(int local_sfd, pSA peer_addr, int addr_len)
{
int cnt = 0;
// 10次连不上就退出程序
while(-1 == connect(local_sfd, peer_addr, addr_len))
{
cnt++;
if(cnt == 10)
{
printf("connect failure!\n");
exit(EXIT_FAILURE);
}
sleep(1);
}
} /* recv and send */
void my_recv(OUT int *recv_len, int peer_sfd, IN_OUT void *base, int len)
{
MY_ASSERT(-1 != (*recv_len = recv(peer_sfd, base, len, 0)), "recv error! \n");
} void my_send(OUT int *send_len, int peer_sfd, void *base, int len)
{
MY_ASSERT(-1 != (*send_len = send(peer_sfd, base, len, 0)), "send error! \n");
} /*---------------------------- 以下针对UDP--------------------------------------------------------*/ void my_recvfrom(OUT int *recvfrom_len, int peer_sfd, IN_OUT void *base, int len, OUT pSA peer_addr, IN_OUT int *addr_len)
{
MY_ASSERT(-1 != (*recvfrom_len = recvfrom(peer_sfd, base, len, 0, peer_addr, addr_len)), "recvfrom failure!\n");
} void my_sendto(OUT int *sendto_len, int peer_sfd, OUT void *base, int len, pSA peer_addr, int addr_len)
{
MY_ASSERT(-1 != (*sendto_len = sendto(peer_sfd, base, len, 0, peer_addr, addr_len)), "sendto failure!\n");
} /* close */
void my_close(int sfd)
{
MY_ASSERT(0 == close(sfd), "close failure!\n");
}
生成动态库
gcc -fPIC -o my_socket.o -c my_socket.c //我的.h文件和.c文件在一个目录下,如果不在,请指定头文件位置
gcc -shared -o libmy_socket.so.1.0 my_socket.o cp./libmy_socket.s0.1.0 /lib
cd /lib
ln -s libmy_socket.so.1.0 libmy_socket.so
我个人将头文件放在主目录的include文件夹下,方便以后查找和使用。(/home/purple/include)
测试代码
server.c
#include "my_socket.h"
#define IP "192.168.153.128"
#define PORT 8888
int main(int argc, char *argv[])
{
int fd_server, fd_client;
int val; //用4个字节的地址空间来传数据
int len;
my_socket(&fd_server, MY_TCP, IP, PORT);
my_listen(fd_server,5);
my_accept(&fd_client, fd_server, NULL, NULL);
printf("accept success!\n");
while(1)
{
my_recv(&len, fd_client, (void*)&val, sizeof(val));
printf("recv data: %d\n", val);
my_send(&len, fd_client, (void*)&val, sizeof(val));
printf("%d has sent!\n\n", val);
}
my_close(fd_client);
my_close(fd_server);
return 0;
}
client.c
#include "my_socket.h"
#define IP "192.168.153.128"
#define MY_PORT 6666
#define SERVER_PORT 8888 int main(int argc, char *argv[])
{
/* socket */
int fd_client;
my_socket(&fd_client, MY_TCP, IP, MY_PORT); /* connect */
SA server_addr;
memset(&server_addr,0,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr.s_addr = inet_addr(IP); my_connect(fd_client, (pSA)&server_addr, sizeof(SA));
printf("connect success!\n"); /* 发送一个数据,并从服务器端返回这个数据 */
int val_in,val_out,len;
while(scanf("%d", &val_in) == 1)
{
my_send(&len,fd_client,(void*)&val_in,sizeof(int));
my_recv(&len,fd_client,(void*)&val_out,sizeof(int));
printf("recv fron server: %d\n", val_out);
} my_close(fd_client);
return 0; }
编译如下
gcc -o server server.c -lmy_socket -I/home/purple/include
gcc -o client client.c -lmy_socket -I/home/purple/include
经测试没有问题。
注意
短路运算(||)必须有返回值,而exit返回值为void,因此头文件中的宏定义,我们没有使用短路运算,而是使用了三目运算符。
Linux网络编程8——对TCP与UDP的简易封装的更多相关文章
- Linux网络编程9——对TCP与UDP的简易封装2.0
具体生成动态库的操作及使用该动态库的操作请参见上篇博文.以下仅仅列出改进版本的代码. 代码 my_socket.h #ifndef __MY_SOCKET_H__ #define __MY_SOCKE ...
- Python网络编程02 /基于TCP、UDP协议的socket简单的通信、字符串转bytes类型
Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes类型 目录 Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes ...
- 网络编程模型及TCP、UDP编程设计
1.Linux网络模型 Linux网络编程--->>>socket套接字的编程 2.TCP网络模型 ...
- 【深入浅出Linux网络编程】 “实践 -- TCP & UDP”
通过上一篇博客的学习,你应该对基于epoll的事件触发机制有所掌握,并且通过阅读sio.c/sio.h应该也学会了如何封装epoll以及如何通过设计令epoll更加实用(用户回调,用户参数). 简单回 ...
- Linux网络编程:基于TCP的程序开发回顾篇《转》
面向连接的TCP程序设计 基于TCP的程序开发分为服务器端和客户端两部分,常见的核心步骤和流程: 其实按照上面这个流程调用系统API确实可以完全实现应用层程序的开发,一点问题没有.可随着时间的推移,你 ...
- 网络编程之基于tcp和udp的套接字
一 udp协议网络编程 DNS:将域名解析成ip地址 SOCK_DGRAM:数据报协议,也是udp协议 udp协议的网络编程的一些用法: recvfrom:接收消息,接收的时一个元组,元组里面的元 ...
- python网络编程(Socket、TCP、UDP)
Socket 是网络编程的一个抽象概念,通常我们用一个Socket表示 "打开了一个网络链接",而打开一个Socket 需要知道目标计算机的IP 地址和端口号,再指定协议类型即可. ...
- python网络编程(通过tcp或者udp协议通信)
1.基于tcp协议传送文件: 客户端: import socketimport osimport jsonimport structclient = socket.socket()client.con ...
- IPv6下网络编程socket, TCP和UDP例子,以及兼容IPV4和IPV6的类
一.TCP socket ipv6与ipv4的区别 服务器端源代码如下: #include <stdio.h> #include <stdlib.h> #include < ...
随机推荐
- android开发系列之代码整洁之道
说起代码整洁之道,想必大家想到更多的是那本经典重构书籍.没错,记得当时自己读那本书的时候,一边结合项目实战,一边结合书中的讲解,确实学到了很多东西,对我自己的编码风格影响极深.随着时间的流逝,书中很多 ...
- linux之mysqlimport的哪些变态事儿
mysqlimport是MySQL导入数据的工具,高效易用. 但掌握不透彻就会有一些变态事情.mysqlimport --host='laswebapp.mdb.game.yy.com' --port ...
- Hadoop之Hive UDAF TopN函数实现
public class GenericUDAFTopNRow extends AbstractGenericUDAFResolver { @Overridepublic GenericUDAFEva ...
- 无法产生coredump的问题
我写了一个必然会崩溃的程序,名字为 test :#include "stdlib.h"#include "unistd.h" int main(){ char ...
- [转]理解与使用Javascript中的回调函数
在Javascript中,函数是第一类对象,这意味着函数可以像对象一样按照第一类管理被使用.既然函数实际上是对象:它们能被“存储”在变量中,能作为函数参数被传递,能在函数中被创建,能从函数中返回. 因 ...
- 14.quartus联合modelsim仿真
在quartus调用modelsim仿真过程中,出现了一个错误,如下所示: Check the NativeLink log file I:/Quartus11.0/Myproject/testi_n ...
- iOS开发HTTPS实现之信任SSL证书和自签名证书
iOS开发HTTPS实现之信任SSL证书和自签名证书 转自:http://www.jianshu.com/p/6b9c8bd5005a/comments/5539345 (收录一下供自己学习用的) 字 ...
- Windows Live Writer教程及代码高亮工具
十分感谢六仙庵对于Windows Live Writer的教程,方便了编辑与发布,教程地址如下: http://www.cnblogs.com/liuxianan/archive/2013/04/13 ...
- Querying mergeinfo requires version 3 of the FSFS filesystem schema
环境: jdk 1.7; svn 3.0.4; TortoiseSVN 1.7.13 Subversion 1.7.10; IntelliJ IDEA 13.1.1;win7 64位系统 之前那个 ...
- linux查看文件权限
ls -l abc (abc是文件名) 那么就会出现相类似的信息,主要都是这些:drwxr-xr-x 一共有10位数 其中: 最前面那个 d 代表的是类型 目录文件 中间那三个 rw- 代表的是所有者 ...