标签归档:c

Socket编程:解决发送与接收数据不全

这个问题是在上个月在做的项目中遇到的问题。项目采用分布式计算,通过网线传输数据。然而却发现用Socket接收和发送数据会出现不全的问题。由于是第一次使用Socket,因此这个问题还是费了点时间去解决。现在把它整理下。


客户端
原来的编程方案:(错误)

//创建套接字
int sock = socket(AF_INET, SOCK_STREAM, 0);
//向服务器(特定的IP和端口)发起请求
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));  //每个字节都用0填充
serv_addr.sin_family = AF_INET;  //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("169.254.48.205");  //具体的IP地址
serv_addr.sin_port = htons(1234);  //端口
connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
//向服务器发送数据
printf("Sending...\n");
write(sock, (char*)conv_ouput, sizeof(float) * 25088);
printf("Send Successful\n");
//关闭套接字
close(sock);

这里有个问题,即是发送端不能保证一次性全部发完数据。因此必须确保发送到能够发全数据。

修改后的编程方案:(正确)

int sock = socket(AF_INET, SOCK_STREAM, 0);
//向服务器(特定的IP和端口)发起请求
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));  //每个字节都用0填充
serv_addr.sin_family = AF_INET;  //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("169.254.48.205");  //具体的IP地址
serv_addr.sin_port = htons(1234);  //端口
connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
//向服务器发送数据
printf("Sending...\n");
int pos = 0;
while(pos < 25088*sizeof(float))
{
	int send_num = send(sock,(char*)conv_ouput+pos, sizeof(float) * 25088, 0);
	if(send_num<=0)
	{
		break;
		printf("send error\n");
	}
	pos += send_num;
}
printf("send num = %d\n",pos);
printf("Send Successful\n");
//关闭套接字
close(sock);

继续阅读

C语言指针理解

最近在做OpenCL的项目,做异构计算。在做的过程中让我不得不重新温习下C语言,不得不去深入理解指针的含义。下面几点我列出了我在《Beginning C:From Novice to Professional》(Ivor Horton)书中学到的几点关于C指针的内容。内容很浅显,但过了4年,重新理解这些简单的知识点,有许多新的体会。所谓大道至简,指针的魅力也许就在这些简单的定义,微小的细节当中。

1-指针是存储地址的变量。
2-编译器必须知道指针所指的变量类型。没有这个信息,就不知道如何处理所指向的内存内容。
3-void*类型的指针可以包含任意类型的地址。
4-未初始化的指针是非常危险的,所以应该在声明指针的时候对他进行初始化。例如:

int *pointer = NULL;
表示不指向任何内存的位置。NULL在多个头文件中都包含。例如stdio.h string.h等。NULL也相当于数字0的指针。即
int *pointer = 0;
与上面的初始化等价。
int *pointer = &number;
pointer变量中存储的是number的地址。
*pointer则是存储在number中的值。
*又称取消引用运算符。

5-可以改变指针指向的地址,因此同一个指针也可以改变不同内存空间里的值。
6-指向常量的指针:

const int *pointer = &value;
不能通过指针改变所指向的值。但可以直接对value进行操作。也可以改变指针指向的地址。

7-常量指针:

int *const pointer = &value;
指针存储的地址不能改变。但可以改变指针指向的内容。

8-指向常量的常量指针:

const int *const pointer = &item;
不能改变存储在指针中的地址,不能改变指向的内容。

 


指针与数组

1-指针和数组似乎完全不同,但他们有非常紧密的关系,有时候还可以互换。
2-数组和指针重要的区别:

可以改变指针包含的地址;
不能改变数组名称引用的地址。
(使用数组名称而不带索引值,就等于引用数组的第一个元素的地址)


动态内存分配

1-int *pointer = (int*)malloc(5*sizeof(int));

malloc是一般函数,可为任意类型的数据分配内存。因此这个函数并不知道要分配的内存空间要做什么用,所以返回的是一个void类型指针。因此要将返回的地址做类型转换。(int*)

2-int *pointer = (int*)calloc(5,sizeof(int));

calloc()函数与malloc()函数相比有两个优点:
-它把内存分配为给定大小的数组;
-它初始化了所分配的内存,所有位都是0;

3-释放动态内存:

动态内存,应在不需要改内存时释放他们。堆上分配的内存会在程序结束时自动释放,但是为了避免出现内存泄漏,应在使用完后释放内存,或者退出程序时释放内存。
free(pointer);
同时应避免两次释放相同的内存区域,因为这种情况下,free操作是不确定的,因此结果也是无法预料的。

使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

Linux内核中设置了一组用于实现各种系统功能的子程序,称为系统调用。用户可以通过系统调用命令在自己的应用程序中调用它们。从某种角度来看,系统调用和普通的函数调用非常相似。区别仅仅在于,系统调用由操作系统核心提供,运行于核心态;而普通的函数调用由函数库或用户自己提供,运行于用户态。


首先man getuid查看相关信息

编程


编译并运行:

嵌入式汇编:

系统调用是怎么工作的?

一般的,进程是不能访问内核的。它不能访问内核所占内存空间也不能调用内核函数。CPU硬件决定了这些(这就是为什么它被称作"保护模式")。系统调用是这些规则的一个例外。其原理是进程先用适当的值填充寄存器,然后调用一个特殊的指令,这个指令会跳到一个事先定义的内核中的一个位置(当然,这个位置是用户进程可读但是不可写的)。在Intel CPU中,这个由中断

0x80

实现。硬件知道一旦你跳到这个位置,你就不是在限制模式下运行的用户,而是作为操作系统的内核–所以你就可以为所欲为。

进程可以跳转到的内核位置叫做sysem_call。这个过程检查系统调用号,这个号码告诉内核进程请求哪种服务。然后,它查看系统调用表(sys_call_table)找到所调用的内核函数入口地址。接着,就调用函数,等返回后,做一些系统检查,最后返回到进程(或到其他进程,如果这个进程时间用尽)。如果你希望读这段代码,它在<内核源码目录>/kernel/entry.S,Entry(system_call)的下一行。

对比结果相同

================================================

Linux 中 x86 的内联汇编 系统调用跟我学(1)
Linux系统调用列表
【linux系统编程】 Linux系统调用概述

> sunfy(与最后申请证书的姓名务必一致) + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000