C++流媒体服务器SRS
https://github.com/ossrs
C++流媒体服务器ZLM
https://github.com/ZLMediaKit/ZLMediaKit
C/C++/QT音视频客户端
https://github.com/metartc/metaRTC
SocketIO
https://github.com/socketio/socket.io-client-cpp
C++操作JSON库:jsoncpp和picojson
https://github.com/open-source-parsers/jsoncpp/tree/master/src/jsontestrunner
https://github.com/kazuho/picojson/tree/master
云风写的C语言协程库
https://github.com/cloudwu/coroutine
京东青龙
https://github.com/6dylan6/jdpro
C++连接redis数据库
https://github.com/redis/hiredis
https://github.com/sewenew/redis-plus-plus
C语言实现traceroute功能
https://github.com/bgylde/traceroute.git
C语言实现ping
https://github.com/coding-fans/linux-network-programming/blob/master/src/c/icmp/ping/ping.c
C语言实现netstat命令功能
https://github.com/LipiLee/netstat/blob/master/netstat.c
十进制,必须以非零数字开头。
八进制,任何以 0 开头的数字(包括普通 0)。
二进制,需要前缀 0b 或 0B。
十六进制,需要前缀 0x 或 0X。
demo:
int aa = 1001;//十进制
printf("aa=%d\n",aa);
int bb = 0b1001;//二进制
printf("bb=%d\n",bb);
int cc = 040;//八进制
printf("cc=%d\n",cc);
int dd = 0x20;//十六进制
printf("dd=%d\n",dd);
打印
aa=1001
bb=9
cc=32
dd=32
两个结构体分配的空间是连续的,可以共用一个起始地址指针pBuff 。
struct HeadDef{
int MsgType;
int TotalLen;
uint8_t pData[0]; //地址指针标识,不占用空间
};
struct MsgDef{
char name[64];
int age;
};
void *pBuff = new char(sizeof(HeadDef) + sizeof(MsgDef));
HeadDef *pMsg = (HeadDef*)pBuff;
pMsg->MsgType = 102;
pMsg->TotalLen = sizeof(HeadDef) + sizeof(MsgDef);
MsgDef *pMsg_body = (MsgDef*)pMsg->pData;
pMsg_body->age = 20;
std::string strname = "chw";
memcpy(pMsg_body->name,strname.c_str(),strname.size());
printf("pMsg->MsgType=%d\n",pMsg->MsgType);
printf("pMsg->TotalLen=%d\n",pMsg->TotalLen);
printf("pMsg_body->age=%d\n",pMsg_body->age);
printf("pMsg_body->name=%s\n",pMsg_body->name);
打印:
pMsg->MsgType=102
pMsg->TotalLen=76
pMsg_body->age=20
pMsg_body->name=chw
//传指针
//传的指针是行参,pNum指针自己的地址和实参指针地址不同,但指针指向的地址相同,因此可以使用行参改变指向地址的内容
//在这里对行参pNum做赋值操作是不会改变实参的
void testformal(int *pNum)
{
printf("行参,指针自己的地址:%p\n",&pNum);
printf("行参,指针指向的地址:%p\n",pNum);
pNum = nullptr;//不会改变实参
}
//传指针引用
//传的是指针的引用,pNum指针地址、指针指向的地址均和实参一致
//在这里,不但可以改变实参指向地址的值,也可以改变实参本身
void testquote(int *&pNum)
{
printf("引用,指针自己的地址:%p\n",&pNum);
printf("引用,指针指向的地址:%p\n",pNum);
pNum = nullptr;//会改变实参
}
int *p = new int;
printf("实参:指针自己的地址:%p\n",&p);
printf("实参:指针指向的地址:%p\n",p);
testformal(p);
printf("%s\n",p == nullptr ? "p == nullptr" : "p != nullptr");
testquote(p);
printf("%s\n",p == nullptr ? "p == nullptr" : "p != nullptr");
打印
实参:指针自己的地址:0x7ffd0fe22f30
实参:指针指向的地址:0x562c56ea1e00
行参,指针自己的地址:0x7ffd0fe22f08
行参,指针指向的地址:0x562c56ea1e00
p != nullptr
引用,指针自己的地址:0x7ffd0fe22f30
引用,指针指向的地址:0x562c56ea1e00
p == nullptr
当数据用于网络发送时,需要进行字节对齐
#pragma pack(push, 1)
//struct{...}
#pragma pack(pop)
int byte2int(uint8_t *data)
{
int value = (int)((data[3] & 0xFF)
| ((data[2] & 0xFF) << 8)
| ((data[1] & 0xFF) << 16)
| ((data[0] & 0xFF) << 24));
return value;
}
调用
char arr[4];
arr[0] = 1;
arr[1] = 1;
arr[2] = 1;
arr[3] = 1;
int num = byte2int((uint8_t *)arr);
printf("num=%d\n",num);
打印
num=16843009
char *str = (char*)"0xff";//不区分大小写,0x可以不写
int n = strtol(str, NULL, 16);
printf("%d\n", n);
打印输出:255
void parse_param(int argc, char **argv)
{
for(int index=0;index<argc;index++)
{
printf("the %d param is [%s]\n",index,argv[index]);
}
}
int argc = 2;
char *argv[2];
argv[0] = (char*)"chw";
argv[1] = (char*)"192.168.1.108";
parse_param(argc, argv);
打印:
the 0 param is [chw]
the 1 param is [192.168.1.108]
#include
int argc = 3;
char *argv[3];
argv[0] = (char*)"testPro";
argv[1] = (char*)"-b";
argv[2] = (char*)"chw";
int opt;
char *c;
while ((opt = getopt(argc, argv, "b:p")) != EOF)
{
switch (opt)
{
case 'b':
c = strdup(optarg);
printf("b=%s\n",c);
free(c);
break;
}
}
打印
b=chw
va_list:一个字符指针,可以理解为指向当前参数的一个指针,取参必须通过这个指针进行。
va_start:对ap进行初始化,让ap指向可变参数表里面的第一个参数。第一个参数是 ap 本身,第二个参数是在变参表前面紧挨着的一个变量,即“…”之前的那个参数;
va_arg: 获取参数。它的第一个参数是ap,第二个参数是要获取的参数的指定类型。按照指定类型获取当前参数,返回这个指定类型的值,然后把 ap 的位置指向变参表中下一个变量的位置;
va_end:释放指针,将输入的参数 ap 置为 NULL。通常va_start和va_end是成对出现。
void test_printf1(char *headData, char *format,...)
{
char buff[4096];
va_list args;
memcpy(buff, headData, strlen(headData));
va_start(args, format);
//将格式化数据从可变参数列表写入缓冲区
vsnprintf(buff+strlen(headData), 1024, format, args);
va_end(args);
printf("%s\n", buff);
}
void test_printf2(int num,...)
{
va_list args;
va_start(args,num);
for(int i = 0; i < num; i++)
printf("%d\n", va_arg(args, int));
va_end(args);
}
test_printf1((char *)"data", (char *)"len is %d, data is %s", 10, "helloworld");
test_printf2(3,100,200,300);
打印
datalen is 10, data is helloworld
100
200
300
fork是复制进程的函数,通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,也可以根据传入参数的不同,做不同的事。
pid_t fork(void);
函数返回值pid_t, 就是int型。
在父进程中,返回新建子进程的进程ID;
在子进程中,返回0;
创建失败,返回负值。
多进程特点
1、fork 子进程后,一般情况是子进程先调度。
2、子进程和父进程共享代码段,堆栈数据和全局数据是独立的,进程空间的各段采用了写时复制技术。
3、父子进程之间可通过信号通信,比如退出时会发信号。
测试代码,循环创建10个子进程。
#include
#include
int main()
{
int pid = 0;
int cnt = 10;
do
{
pid = fork();
if(pid < 0)
{
continue;
}
if(pid == 0)
{
break;
}
if(pid > 0)
{
cnt --;
}
}
while(cnt > 0);
printf("pid=%d,rpid=%d\n",pid,getpid());
while(1){}
}
打印
pid=0,rpid=3622
pid=3628,rpid=3618
pid=0,rpid=3628
pid=0,rpid=3623
pid=0,rpid=3619
pid=0,rpid=3627
pid=0,rpid=3624
pid=0,rpid=3625
pid=0,rpid=3621
pid=0,rpid=3626
pid=0,rpid=3620
内存是由字节组成的,每个字节都有一个地址编号。
指针变量主要是存放相同数据类型的变量的首地址,这里的地址就是指内存中某个字节的编号,而这个编号的确定是由地址总线决定的,操作系统的位数决定了指针变量所占的字节数。
如果是32位操作系统,也就是地址总线是32位,则它的寻址范围就是02^32(4GB,所以32位系统最多配4G内存,多了也没有用),每一个字节的编址就会由32个0或者1组成。
例:第1个字节的编址是32个0,最后1个的编址是32个1。一个字节有8位,32位则需要4个字节。
64 位 CPU 寻址范围则很大,理论最大的寻址空间为 2^64。
不管是什么数据类型:
1、在32位操作系统下,指针是占4个字节空间大小。
2、在64位操作系统下,指针是占8个字节空间大小。
以int型指针为例。
//1.int型指针
int *p=new int;
*p = 12;
printf("*p=%d\n",*p);
//释放
delete p;
p = nullptr;
//2.int型一维数组
int iArrNum = 5;
int *pArr=new int [iArrNum];//只动态分配空间,未初始化
memset(pArr,0,iArrNum*sizeof(int));
for(int index=0;index<iArrNum;index++)
printf("pArr[%d]=%d\n",index,pArr[index]);
//释放
delete []pArr;
pArr = nullptr;
//3.int型二维数组
int row = 3;//行
int col = 4;//列
//分配一个指针数组,首地址保存在pInt
int **pInt=new int* [row];
//为指针数组的每个元素分配一个数组
for(int i=0;i<row;i++)
{
pInt[i]=new int [col];
}
//遍历
int n = 0;
for(int i=0;i<row;i++)
for(int j=0;j<col;j++)
pInt[i][j] = n++;
for(int i=0;i<row;i++)
for(int j=0;j<col;j++)
printf("pInt[%d][%d]=%d\n",i,j,pInt[i][j]);
//释放
for(int i=0;i<row;i++)
{
delete []pInt[i];
}
delete []pInt;
打印
*p=12
pArr[0]=0
pArr[1]=0
pArr[2]=0
pArr[3]=0
pArr[4]=0
pInt[0][0]=0
pInt[0][1]=1
pInt[0][2]=2
pInt[0][3]=3
pInt[1][0]=4
pInt[1][1]=5
pInt[1][2]=6
pInt[1][3]=7
pInt[2][0]=8
pInt[2][1]=9
pInt[2][2]=10
pInt[2][3]=11
正数的表示法,先转换成二进制,在前面补0。
例如5的表示法:
00000000 00000000 00000000 00000101
在计算机中,负数以原码的补码形式表达
1、原码
用符号位和数值表示带符号数,正数的符号位用“0”表示,负数的符号位用“1”表示,数值部分用二进制形式表示。
例如
00000000 00000000 00000000 00000101 是 5的原码。
10000000 00000000 00000000 00000101 是-5的原码。
2、反码
正数的反码与原码相同,负数的反码为对该数的原码除符号位外各位取反。
例如
正数00000000 00000000 00000000 00000101 的反码还是 00000000 00000000 00000000 00000101
负数10000000 00000000 00000000 00000101 的反码则是 11111111 11111111 11111111 11111010。
3、补码
正数的补码与原码相同,负数的补码为对该数的原码除符号位外各位取反,然后在最后一位加1。
例如
10000000 00000000 00000000 00000101 的反码是:11111111 11111111 11111111 11111010
补码为:
11111111 11111111 11111111 11111010 + 1 = 11111111 11111111 11111111 11111011
-5 在计算机中表达为:11111111 11111111 11111111 11111011。转换为十六进制:0xFFFFFFFB。
举例,int类型-1在计算机中表示法:
-1的原码:10000000 00000000 00000000 00000001
得反码: 11111111 11111111 11111111 11111110(除符号位按位取反)
得补码: 11111111 11111111 11111111 11111111
位是数据存储的最小单位,简记为b,也称为比特,每个0或1就是一个位(bit)。
位运算操作符:& (按位与)、| (按位或)、^ (按位异或)、~ (按位取反)、>> (按位右移)、<< (按位左移)。
&(按位与)
如果两个相应的二进制位都为1,则该位的结果值为1;否则为0。
| (按位或)
如果两个相应的二进制位只要有一个是1,结果就是1;否则为0。
~(按位取反)
每一位进行取反运算,1变成0,0变成1。
^(按位异或)
两个相同的数会变成0,反之是1
>>(按位右移)
把二进制位整体向右移动,右移等于除以2的N次方,N为右移的位数。
<<(按位左移)
把二进制位整体向左移动,左移等于乘以2的N次方,N为左移的位数
demo
int aa = 0b1001;//9
int bb = 0b1110;//14
int yu = aa & bb;//1000,8
int huo = aa | bb;//1111,15
int fei = ~aa; //-10
int yihuo = aa ^ bb;//111,7
int youyi = aa >> 1;//100,4
int zuoyi = aa << 1;//10010,18
printf("aa=%d\n",aa);
printf("bb=%d\n",bb);
printf("yu=%d\n",yu);
printf("huo=%d\n",huo);
printf("fei=%d\n",fei);
printf("yihuo=%d\n",yihuo);
printf("youyi=%d\n",youyi);
printf("zuoyi=%d\n",zuoyi);
打印
aa=9
bb=14
yu=8
huo=15
fei=-10
yihuo=7
youyi=4
zuoyi=18
linux系统
#include
/* 获取时间,1970年1月1日到现在的时间 */
struct timeval time;
gettimeofday(&time, NULL);
printf("s: %ld, ms: %ld\n", time.tv_sec, (time.tv_sec*1000 + time.tv_usec/1000));
windows系统
#include
SYSTEMTIME timenow;
GetLocalTime(&timenow); printf("hour=%u,minute=%u,second=%u,Milliseconds=%d\n",timenow.wHour,timenow.wMinute,timenow.wSecond,timenow.wMilliseconds);
linux
#include
#include
#include
int sleep_time = 5;
cout << "sleep before time: " << time(NULL) << endl;
sleep(sleep_time);//睡眠单位,秒
cout << "sleep after time: " << time(NULL) << endl;
sleep_time = 10*1000;
cout << "======================" << endl;
struct timeval tv;
gettimeofday(&tv,NULL);
cout << "usleep before time: " << tv.tv_sec<<"s,"<<tv.tv_usec<<" 微秒"<<endl;
usleep(sleep_time);//睡眠单位,微秒
gettimeofday(&tv,NULL);
cout << "usleep after time: " << tv.tv_sec<<"s,"<<tv.tv_usec<<" 微秒"<<endl;
打印
sleep before time: 1675737566
sleep after time: 1675737571
======================
usleep before time: 1675737571s,340562 微秒
usleep after time: 1675737571s,351354 微秒
windows
#include
#include
SYSTEMTIME timenow;
GetLocalTime(&timenow);
printf("hour=%u,minute=%u,second=%u,Milliseconds=%d\n",timenow.wHour,timenow.wMinute,timenow.wSecond,timenow.wMilliseconds);
Sleep(10);//单位毫秒
GetLocalTime(&timenow);
printf("hour=%u,minute=%u,second=%u,Milliseconds=%d\n",timenow.wHour,timenow.wMinute,timenow.wSecond,timenow.wMilliseconds);
打印
hour=10,minute=32,second=23,Milliseconds=515
hour=10,minute=32,second=23,Milliseconds=526
方法1:rand()
使用srand()设置种子,rand()生成随机数,如果种子一样则会生成相同的随机数;如果不设置种子则默认初始种子为1,生成的随机数做为新种子用于下次生成随机数。rand()生成的是伪随机数。
struct timeval time;
gettimeofday(&time, NULL);
unsigned long ms = (time.tv_sec*1000 + time.tv_usec/1000);
srand(ms);//设置种子
int random = rand();
printf("random=%d\n",random);
usleep(100*10);
方法2:random_device
random_device 是标准库提供到一个非确定性随机数生成器,使用硬件作为随机数来源,故其调用代价较高,一般用来产生随机数种子。
random_device提供()操作符,用来返回一个min()到max()之间的一个高质量随机数,可以理解为真随机数。
std::random_device rd;//做为随机数种子
//下面几种是标准库提供的伪随机数生成器(种子相同则随机数相同),使用random_device生成的真随机数做为种子是常用方法。
///1.mt19937 是标准库提供的采用梅森旋转算法的伪随机数生成器,可以快速产生高质量到随机数。
std::mt19937 mt(rd());
for(int n = 0; n < 10; n++)
std::cout << mt() << std::endl;
///2.default_random_engine 是标准库提供的默认随机数生成器,其实现和编译器有关。
std::default_random_engine r_eng(rd());
for (int i = 0; i < 10; ++i)
std::cout << r_eng() << std::endl;
///3.minstd_rand 是标准库提供的采用线性同余算法的伪随机数生成器。
std::minstd_rand r_minstd_rand(rd());
for (int i = 0; i < 10; ++i)
std::cout << r_minstd_rand() << std::endl;
///4.ranlux24_base 是标准库提供的采用带进位减法的伪随机数生成器。
std::ranlux24_base r_ranlux24_base(rd());
for (int i = 0; i < 10; ++i)
std::cout << r_ranlux24_base() << std::endl;
int _Index = -1;
int _taskpoll = 6;
for(int index=0;index<10;index++)
{
_Index++;
_Index %= _taskpoll;
printf("_Index=%d\n",_Index);
}
打印
_Index=0
_Index=1
_Index=2
_Index=3
_Index=4
_Index=5
_Index=0
_Index=1
_Index=2
_Index=3
#include
int printf(const char *restrict format, ...);
int fprintf(FILE *restrict fp, const char *restrict format, ...);
printf将格式化写到标准输出,fprintf写至指定的流,默认输出到屏幕。
#include
setbuf(stdout,nullptr);//设置无缓存区,直接打印
setbuf(stderr,nullptr);
int day = 27;
fprintf(stdout, "Hello:%d \n",day);
const char *msg = "error hapd";
fprintf(stderr, "World!:%s\n",msg);
打印
Hello:27
World!:error hapd
可以把流重定向到指定文件,下面运行可执行文件,输出流重定向到tmp.txt文件。
./fpint > tmp.txt
linux系统
printf("mainwindow thread tid = %lu\n", pthread_self());
#include
printf("mainwindow,pid:%u, tid:%u\n",(unsigned int)getpid(), (unsigned int)gettid());
#include
printf("mainwindow,ThreadID: %lu\n", std::this_thread::get_id());
windows系统
#include
printf("mainwindow,ThreadID: %lu\n", std::this_thread::get_id());
#include //cout需要的头文件
using namespace std;
//char*转string
char ary[1024]="abcdefg";
string str=ary;
cout<<"str="<<str<<endl;//str=abcdefg
//string转char*
char ary2[1024];
strcpy(ary2,str.c_str());//建议用strcpy_s
printf("ary2=%s\n",ary2);//ary2=abcdefg
//int转string,其他类型的整型和浮点型均可使用
int i = 42;
double d = 42.7;
string str = to_string(i);
string str2 = to_string(d);
printf("str=%s,str2=%s\n",str.c_str(),str2.c_str());//str=42,str2=42.700000
//string转int,也可转为其他类型的整型和浮点型
int ii = stoi(str); //int
long ll = stol(str); //long
unsigned long ull = stoul(str); //unsigned long
long long lll = stoll(str); //long long
unsigned long long ulll = stoull(str); //unsigned long long
float ff = stof(str); //float
double dd = stod(str); //double
long double ldd = stold(str); //long double
#include //linux(全路径,不包含可执行文件名)
#include //win(包含可执行文件名的全路径)
#define MAXPATH 1000
char buffer[MAXPATH];
getcwd(buffer,MAXPATH);
printf("The current directoryis:%s\n",buffer);
//int型大小4字节,数值范围:-2^(32-1) – 2^(32-1)-1(即 -2147483648 ~ 2147483647)
int _int_max = 2147483647;
int _int_min = -2147483648 ;
printf("_int_max=%d,_int_max+1=%d\n",_int_max,_int_max+1);//_int_max=2147483647,_int_max+1=-2147483648
printf("_int_min=%d,_int_min-1=%d\n",_int_min,_int_min-1);//_int_min=-2147483648,_int_min-1=2147483647
//short型大小2字节,数值范围:-2^(16-1) – 2^(16-1) -1 (即 -32768 ~ 32767)
short _short_max = 32767;
short _short_min = -32768;
printf("_short_max=%hd,_short_max+1=%hd\n",_short_max,_short_max+1);//_short_max=32767,_short_max+1=-32768
printf("_short_min=%hd,_short_min-1=%hd\n",_short_min,_short_min-1);//_short_min=-32768,_short_min-1=32767
//long型大小4字节,数值范围:-2^(32-1) – 2^(32-1)-1(即 -2147483648 ~ 2147483647)
long _long_max = 2147483647;
long _long_min = -2147483648 ;
printf("_long_max=%ld,_long_max+1=%ld\n",_long_max,_long_max+1);//_long_max=2147483647,_long_max+1=-2147483648
printf("_long_min=%ld,_long_min-1=%ld\n",_long_min,_long_min-1);//_long_min=-2147483648,_long_min-1=2147483647
//long long型大小8字节,数值范围:-2^(64-1) ~ 2^(64-1)-1(即 -9223372036854775808 ~ 9223372036854775807
long long _long_long_max = 9223372036854775807;
long long _long_long_min = -9223372036854775808;
//_long_long_max=9223372036854775807,_long_long_max+1=-9223372036854775808
//_long_long_min=-9223372036854775808,_long_long_min-1=9223372036854775807
printf("_long_long_max=%lld,_long_long_max+1=%lld\n",_long_long_max,_long_long_max+1);
printf("_long_long_min=%lld,_long_long_min-1=%lld\n",_long_long_min,_long_long_min-1);
//unsigned int型大小4字节,数值范围:0 – 2^(32)-1 (即 0~4294967295)
unsigned int _unsigned_int_max = 4294967295;
unsigned int _unsigned_int_min = 0 ;
printf("_unsigned int_max=%u,_unsigned int_max+1=%u\n",_unsigned_int_max,_unsigned_int_max+1);//_unsigned int_max=4294967295,_unsigned int_max+1=0
printf("_unsigned int_min=%u,_unsigned int_min-1=%u\n",_unsigned_int_min,_unsigned_int_min-1);//_unsigned int_min=0,_unsigned int_min-1=4294967295
//unsigned short型大小2字节,数值范围:0 ~ 2^16 -1 (即 0~65535)
unsigned short _unsigned_short_max = 65535;
unsigned short _unsigned_short_min = 0;
printf("_unsigned_short_max=%hu,_unsigned short_max+1=%hu\n",_unsigned_short_max,_unsigned_short_max+1);//_unsigned_short_max=65535,_unsigned short_max+1=0
printf("_unsigned_short_min=%hu,_unsigned short_min-1=%hu\n",_unsigned_short_min,_unsigned_short_min-1);//_unsigned_short_min=0,_unsigned short_min-1=65535
//long型大小4字节,数值范围:0 – 2^(32)-1 (即 0~4294967295)
unsigned long _unsigned_long_max = 4294967295;
unsigned long _unsigned_long_min = 0;
printf("_unsigned_long_max=%lu,_unsigned_long_max+1=%lu\n",_unsigned_long_max,_unsigned_long_max+1);//_unsigned_long_max=4294967295,_unsigned_long_max+1=0
printf("_unsigned_long_min=%lu,_unsigned_long_min-1=%lu\n",_unsigned_long_min,_unsigned_long_min-1);//_unsigned_long_min=0,_unsigned_long_min-1=4294967295
//unsigned long long型大小8字节,数值范围:0~2^64-1(即 0 ~ 18446744073709551615)
unsigned long long _unsigned_long_long_max = 18446744073709551615;
unsigned long long _unsigned_long_long_min = 0;
//_unsigned_long_long_max=18446744073709551615,_unsigned_long_long_max+1=0
//_unsigned_long_long_min=0,_unsigned_long_long_min-1=18446744073709551615
printf("_unsigned_long_long_max=%llu,_unsigned_long_long_max+1=%llu\n",_unsigned_long_long_max,_unsigned_long_long_max+1);
printf("_unsigned_long_long_min=%llu,_unsigned_long_long_min-1=%llu\n",_unsigned_long_long_min,_unsigned_long_long_min-1);
/// 常用整型typedef
// typedef short int16_t;
// typedef unsigned short uint16_t;
// typedef int int32_t;
// typedef unsigned uint32_t;
// typedef long long int64_t;
// typedef unsigned long long uint64_t;
g++ tcp_client.c -lpthread -o cli
./cli
tcp_client.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef _WIN32
#include
#include
#define socklen_t int
#else
#include
#include
#include
#include
#include
#endif
typedef struct {
int32_t fd;
int32_t localPort;
int32_t remotePort;
int32_t isStart;
int32_t isLoop;
pthread_t threadId;
//char serverIp[30];
void* user;
struct sockaddr_in local_addr;
struct sockaddr_in remote_addr;
void (*receive)(char *data, int32_t nb_data,void* user);
}TcpHandle;
int32_t create_tcpClient(TcpHandle *tcpClient, char *serverIp, int32_t serverPort, int32_t plocalPort)
{
if (tcpClient == NULL) return -1;
tcpClient->localPort = plocalPort;
tcpClient->fd = -1;
tcpClient->remotePort = serverPort;
#ifdef _WIN32
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD(2, 2);
WSAStartup(wVersionRequested, &wsaData);//初始化socket库
#endif
tcpClient->local_addr.sin_family = AF_INET;
tcpClient->local_addr.sin_port = htons(tcpClient->localPort);
// lcl_addr.sin_addr.s_addr=inet_addr(ip);
tcpClient->local_addr.sin_addr.s_addr = INADDR_ANY;
if((tcpClient->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket");
return -2;
}
tcpClient->remote_addr.sin_family = AF_INET;
tcpClient->remote_addr.sin_port = htons(tcpClient->remotePort);
#ifdef _WIN32
tcpClient->remote_addr.sin_addr.S_un.S_addr=inet_addr(serverIp);
#else
tcpClient->remote_addr.sin_addr.s_addr = inet_addr(serverIp);//将点分十进制IP转换成网络字节序IP
#endif
if(connect(tcpClient->fd, (struct sockaddr *)&tcpClient->remote_addr, sizeof(tcpClient->remote_addr)) < 0)
{
perror("connect");
return -3;
}
printf("connect success\n");
return 0;
}
void* recv_thread_tcpClient(void *obj) {
#ifdef _WIN32
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD(2, 2);
WSAStartup(wVersionRequested, &wsaData);
#endif
TcpHandle *ptcpClient = (TcpHandle*) obj;
ptcpClient->isStart = 1;
#ifdef _WIN32
int32_t timeout=200;
setsockopt(ptcpClient->fd, SOL_SOCKET, SO_RCVTIMEO, (const char*) &timeout, sizeof(timeout));
#else
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 20000; // 20 ms
setsockopt(ptcpClient->fd, SOL_SOCKET, SO_RCVTIMEO, (const char*) &tv, sizeof(struct timeval));
#endif
char buffer[2048] = { 0 };
ptcpClient->isLoop = 1;
int32_t len = 0;
socklen_t src_len = sizeof(struct sockaddr_in);
while (ptcpClient->isLoop)
{
struct sockaddr_in src;
memset(&src, 0, src_len);
memset(buffer, 0, 2048);
if ((len = recvfrom(ptcpClient->fd, buffer, 2048, 0, (struct sockaddr*) &src, &src_len)) > 0)
{
printf("buffer=%s\n",buffer);
}
}
ptcpClient->isStart = 0;
#ifdef _WIN32
closesocket(ptcpClient->fd);
#else
close(ptcpClient->fd);
#endif
ptcpClient->fd = -1;
return NULL;
}
TcpHandle *pTcpHandle;
int main()
{
pTcpHandle = (TcpHandle *)malloc(sizeof(TcpHandle));
create_tcpClient(pTcpHandle,(char*)"127.0.0.1",9090,0);
pthread_create(&pTcpHandle->threadId, 0, recv_thread_tcpClient, pTcpHandle);
std::string msg = "hello";
send(pTcpHandle->fd,msg.c_str(),msg.size(),0);
while(1){}
}
g++ tcp_server.c -lpthread -o ser
./ser
tcp_server.c
#include
#include
#include
#include
#include
#include
#include
#ifdef _WIN32
#define _WIN32_WINNT 0x0600
#include "windows.h"
#include
#include
#define socklen_t int
#else
#include
#include
#include
#include
#include
#include
#endif
#ifndef _WIN32
#include
#define GetSockError() errno
#define SetSockError(e) errno = e
#define closesocket(s) close(s)
#else
#define GetSockError() WSAGetLastError()
#define SetSockError(e) WSASetLastError(e)
#define setsockopt(a,b,c,d,e) (setsockopt)(a,b,c,(const char *)d,(int)e)
#endif
typedef struct {
int32_t serverfd;
int32_t connFd;
int32_t isStart;
int32_t isLoop;
pthread_t threadId;
int32_t serverPort;
void* user;
char remoteIp[32];
struct sockaddr_in local_addr;
struct sockaddr_in remote_addr;
void (*receive)(char *data, int32_t nb_data,void* user,int32_t clientFd);
void (*startStunTimer)(void* user);
}TcpServer;
int32_t create_tcpServer(TcpServer *tcpServer, int32_t listenPort)
{
if (tcpServer == NULL)
return 1;
tcpServer->serverfd = -1;
tcpServer->serverPort = listenPort;
tcpServer->local_addr.sin_family = AF_INET;
tcpServer->local_addr.sin_port = htons(listenPort);
#ifdef _WIN32
tcpServer->local_addr.sin_addr.S_un.S_addr=INADDR_ANY;
#else
tcpServer->local_addr.sin_addr.s_addr = INADDR_ANY;
#endif
return 0;
}
void* run_tcpConnClient_thread(void *obj)
{
TcpServer* tcpServer=(TcpServer*)obj;
int connfd=tcpServer->connFd;
char remoteIp[32]={0};
strcpy(remoteIp,tcpServer->remoteIp);
int32_t nBytes =0;
char buffer[2048] = { 0 };
while (tcpServer->isLoop)
{
memset(buffer, 0, 2048);
nBytes = recv(connfd, buffer, 2048, 0);
if (nBytes > 0)
{
printf("buffer=%s\n",buffer);
std::string msg = "back";
send(connfd,msg.c_str(),msg.size(),0);
}
else if (nBytes == -1)
{
int32_t sockerr = GetSockError();
if (sockerr == EINTR)
continue;
if (sockerr == EWOULDBLOCK || sockerr == EAGAIN)
{
nBytes = 0;
continue;
}
#ifdef Q_OS_LINUX
printf("%s, recv returned %d. GetSockError(): %d (%s)\n", __FUNCTION__, nBytes, sockerr, strerror(sockerr));
#endif
continue;
}
}
closesocket(connfd);
return NULL;
}
void* run_tcpServer_thread(void *obj) {
#ifdef _WIN32
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD(2, 2);
WSAStartup(wVersionRequested, &wsaData);
#endif
TcpServer *tcpServer = (TcpServer*) obj;
tcpServer->isStart = 1;
tcpServer->serverfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
#ifdef _WIN32
int32_t timeout=200;
setsockopt(tcpServer->serverfd, SOL_SOCKET, SO_RCVTIMEO, (const char*) &timeout, sizeof(timeout));
#else
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 200000; // 200 ms
setsockopt(tcpServer->serverfd, SOL_SOCKET, SO_RCVTIMEO, (const char*) &tv,
sizeof(struct timeval));
#endif
printf("http tcp server is starting,listenPort==%d\n", tcpServer->serverPort);
int bReuseaddr = 1;
setsockopt( tcpServer->serverfd, SOL_SOCKET, SO_REUSEADDR, ( const char* )&bReuseaddr, sizeof( int ) );
if (bind(tcpServer->serverfd, (struct sockaddr*) &tcpServer->local_addr,sizeof(struct sockaddr_in)) < 0) {
printf("http server bind error(%d)",GetSockError());
exit(1);
}
listen(tcpServer->serverfd, 5);
tcpServer->isLoop = 1;
socklen_t src_len = sizeof(struct sockaddr_in);
while (tcpServer->isLoop)
{
struct sockaddr_in src;
memset(&src, 0, src_len);
int connfd = accept(tcpServer->serverfd, (struct sockaddr*) &src, &src_len);
if(connfd>-1)
{
pthread_t th;
tcpServer->connFd=connfd;
memset(tcpServer->remoteIp,0,sizeof(tcpServer->remoteIp));
#ifdef _WIN32
inet_ntop(AF_INET,&src.sin_addr.s_addr, tcpServer->remoteIp, sizeof(tcpServer->remoteIp));
#else
inet_ntop(AF_INET,&src.sin_addr.s_addr, tcpServer->remoteIp, sizeof(tcpServer->remoteIp));
#endif
pthread_create(&th, 0, run_tcpConnClient_thread, tcpServer);
}
}
tcpServer->isStart = 0;
#ifdef _WIN32
closesocket(tcpServer->serverfd);
#else
close(tcpServer->serverfd);
#endif
tcpServer->serverfd = -1;
return NULL;
}
int main()
{
TcpServer* pTcpServer = (TcpServer *)malloc(sizeof(TcpServer));
create_tcpServer(pTcpServer,9090);
pthread_create(&pTcpServer->threadId, 0, run_tcpServer_thread, pTcpServer);
while(1){}
}