当前位置:  技术问答>linux和unix

求教一些关于socket的系列知识,以及一点内核知识。

    来源: 互联网  发布时间:2016-02-12

    本文导语:  1)socket 通讯编程究竟指什么?其本质是什么?和具体的协议(tcp,udp,icmp,ip)有什么关系呢?为什么叫socket(插头)呢?socket_id 代表一个什么东东?应用程序中的SOCKET与内核是怎么交换数据的呢?现在的网卡都是全双工的...

1)socket 通讯编程究竟指什么?其本质是什么?和具体的协议(tcp,udp,icmp,ip)有什么关系呢?为什么叫socket(插头)呢?socket_id 代表一个什么东东?应用程序中的SOCKET与内核是怎么交换数据的呢?现在的网卡都是全双工的,用两个进程对一个socket_id实现同时发和收可以吗,就是一个发另一个收?请说述一下,最好能举个例子。
2)通过socket发送数据时,这些数据是被马上发出的吗?还是要放在缓存一会?比如使用数据报发送,也就是UDP协议。
3)操作系统的时间片和CPU的中断响应时间有什么关系?UNIX的时间片是100US,那是不是可以认为用POLL或者SELECT来做定时器,最多只能精确到100US?
谢谢你了。

|
先简单说下 TCP  和  UDP
TCP(Transfer Control Protocol)传输控制协议是一种面向连接的协议,当我们的网络程序使用这个协议的时候,网络可以保证我们的客户端和服务端的连接是可靠的,安全的.

UDP(User Datagram Protocol)用户数据报协议是一种非面向连接的协议,这种协议并不能保证我们的网络程序的连接是可靠的,所以我们现在编写的程序一般是采用TCP 协议的

在linux 套接字编程是通过以下五个关键函数实现的:
socket
int socket(int domain, int type,int protocol)

domain:说明我们网络程序所在的主机采用的通讯协族(AF_UNIX 和AF_INET 等). 
AF_UNIX 只能够用于单一的Unix 系统进程间通信,
AF_INET 是针对Internet 的,因而可以允许在远程 主机之间通信

type:我们网络程序所采用的通讯协议(SOCK_STREAM,SOCK_DGRAM 等) 
SOCK_STREAM表明我们用的是TCP 协议,这样会提供按顺序的,可靠,双向,面向连接的比特流.
SOCK_DGRAM 表明我们用的是UDP 协议,这样只会提供定长的,不可靠,无连接的通信.

protocol:由于我们指定了type,所以这个地方我们一般只要用0 来代替就可以了

成功时返回文件描述符,失败时返回-1,看errno 可知道出错的详细情况.

bind  [绑]
int bind(int sockfd, struct sockaddr *my_addr, int addrlen)

sockfd:是由socket 调用返回的文件描述符.

addrlen:是sockaddr 结构的长度.

my_addr:是一个指向sockaddr 的指针. 在;中有 sockaddr 的定义
struct sockaddr{
unisgned short as_family;
char sa_data[14];
};
不过由于系统的兼容性,我们一般不用这个头文件,而使用另外一个结构(struct sockaddr_in) 来代替.在;中有sockaddr_in 的定义
struct sockaddr_in{
unsigned short sin_family;
unsigned short int sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
}
sin_family 一般为AF_INET,
sin_addr 设置为INADDR_ANY 表示可以 和任何的主机通信,
sin_port 是我们要监听的端口号.
sin_zero[8]是用来填充的

bind 将本地的端口同socket 返回的文件描述符捆绑在一起.成功是返回0,失败的情况和socket 一样

listen
int listen(int sockfd,int backlog)
sockfd:是bind 后的文件描述符.
backlog:设置请求排队的最大长度.

listen 函数将bind 的文件描述符变为监听套接字.返回的情况和bind 一样.



accept
int accept(int sockfd, struct sockaddr *addr,int *addrlen)
sockfd:是listen 后的文件描述符.
addr,addrlen 是用来给客户端的程序填写的,服务器端只要传递指针就可以了. 

accept 成功时返回最后的服务器端的文件描述符,这个时候服务器端可以向该描述符写信息了. 失败时返回-1


connect
int connect(int sockfd, struct sockaddr * serv_addr,int addrlen)
sockfd:socket 返回的文件描述符.
serv_addr:储存了服务器端的连接信息,其中sin_add 是服务端的地址
addrlen:serv_addr 的长度

connect 函数是客户端用来同服务端连接的.成功时返回0,sockfd 是同服务端通讯的文件
描述符 失败时返回-1;


|
同意。
补充一下最后一个,答案也是没有关系。详细可以看看kernel/sched.c就明白了。

----------------

 i_noname(晚九朝五) ( ) 信誉:100    Blog   加为好友  2007-6-17 18:28:46  得分: 0  
 
 
   
个人理解,不保证正确性

1:
socket是TCP协议栈提供给用户的接口,就像open/read等,属于系统调用。socket_id其实就是一个file descriptor。应用层通过系统调用与内核进行数据交换。
2:
发送方式可以设置,TCP协议栈默认是使用缓存的,你可以设成不使用。
3:
时间片大小是根据进程调度策略来定义的,和CPU中断响应时间没啥关系。
不是

  
 

|
个人理解,不保证正确性

1:
socket是TCP协议栈提供给用户的接口,就像open/read等,属于系统调用。socket_id其实就是一个file descriptor。应用层通过系统调用与内核进行数据交换。
2:
发送方式可以设置,TCP协议栈默认是使用缓存的,你可以设成不使用。
3:
时间片大小是根据进程调度策略来定义的,和CPU中断响应时间没啥关系。
不是

|

我也理解一下
socket编程实际上就是进程间编程,不仅仅指网络编程.
不管你使用的那种协议,当你发送/接收一个数据包时,实际上时调用的一个系统调用sys_socket(),此调用会根据你
的设置把数据包放入/取出内核缓冲区,由网卡的驱动程序根据情况来把数据转换成电平信号传送出去,你讲的
全双工/半双工一般是指的电平信号的发送/和接收,属于较低层的概念.

|
再给个简单例子,你自己结合着,理解下:
我也是刚刚学习的,建议你买本书看看:
/******* 服务器程序 (server.c) ************/
#include ;
#include ;
#include ;
#include ;
#include ;
#include ;
#include ;
#include ;
int main(int argc, char *argv[])
{
int sockfd,new_fd;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
int sin_size,portnumber;
char hello[]="Hello! Are You Fine?n";

portnumber=8888;

/* 服务器端开始建立socket 描述符 */
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
fprintf(stderr,"Socket error:%sna",strerror(errno));
exit(1);
}
/* 服务器端填充 sockaddr 结构 */
bzero(&server_addr,sizeof(struct sockaddr_in));
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
server_addr.sin_port=htons(portnumber);
/* 捆绑sockfd 描述符 */
if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
{
fprintf(stderr,"Bind error:%sna",strerror(errno));
exit(1);
}
/* 监听sockfd 描述符 */
if(listen(sockfd,5)==-1)
{
fprintf(stderr,"Listen error:%sna",strerror(errno));
exit(1);
}
while(1)
{
/* 服务器阻塞,直到客户程序建立连接 */
sin_size=sizeof(struct sockaddr_in);
if((new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size
))==-1)
{
fprintf(stderr,"Accept error:%sna",strerror(errno));
exit(1);
}
fprintf(stderr,"Server get connection from %sn",
inet_ntoa(client_addr.sin_addr));
if(write(new_fd,hello,strlen(hello))==-1)
{
fprintf(stderr,"Write Error:%sn",strerror(errno));
exit(1);
}
/* 这个通讯已经结束 */
close(new_fd);
/* 循环下一个 */
}
close(sockfd);
exit(0);
}
/******* 客户端程序 client.c ************/
#include ;
#include ;
#include ;
#include ;
#include ;
#include ;
#include ;
#include ;
int main(int argc, char *argv[])
{
int sockfd;
char buffer[1024];
struct sockaddr_in server_addr;
struct hostent *host;
int portnumber,nbytes;

if((host=gethostbyname("localhost")==NULL)
{
fprintf(stderr,"Gethostname errorn");
exit(1);
}

portnumber=8888;


/* 客户程序开始建立 sockfd 描述符 */
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
fprintf(stderr,"Socket Error:%san",strerror(errno));
exit(1);
}
/* 客户程序填充服务端的资料 */
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(portnumber);
server_addr.sin_addr=*((struct in_addr *)host->h_addr);
/* 客户程序发起连接请求 */
if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr)
)==-1)
{
fprintf(stderr,"Connect Error:%san",strerror(errno));
exit(1);
}
/* 连接成功了 */
if((nbytes=read(sockfd,buffer,1024))==-1)
{
fprintf(stderr,"Read Error:%sn",strerror(errno));
exit(1);
}
buffer[nbytes]='';
printf("I have received:%sn",buffer);
/* 结束通讯 */
close(sockfd);
exit(0);
}


|
1 用两个进程对一个socket_id实现同时发和收可以吗,当然可以的

2 不是,要到系统的缓冲区,然后再由系统发送出去的

|
socket不仅可以应用TCP协议,还可以应用UDP协议,只不过tcp是有连接的,udp是无连接的罢了。
至于他们的传输,应该说在我们的程序中就只调用send(),recv(),一类函数而已,我们自己的基本是没有做什么事情的.

|
对于上面那个服务器端程序,while(1),我感觉用这样的例子教人,不太好,难道就让这个程序独占系统资源,一直等在这里吗?虽然很多书上都举这样的例子,但是好像在实际中,没有人这样作的,如果你的服务器在等待客户端连接的时候,就像死机了一样,不能处理其它事情,我想,也没有客户会接受吧。

|
回楼上:没你想得那么严重
阻塞式的socket,accept如果不成功,该线程就会被阻塞,完全不占CPU,直到有连接进来,线程才会重新被唤醒,所以不会出现你想像中,像死机一样的情形。

    
 
 

您可能感兴趣的文章:

  • (高分求教)学习J2EE前所应具有的知识.
  • 高分求教基础知识:大家谁知道哪个学习哪个版本UNIX好,在微机上怎么安装?可以下载安装程序吗?
  • [求教]内核加载模块后,这部分内容编译在内核里的吗?
  • 求教内核编译网络部分配置
  • 内核编程问题求教!!!!
  • 求教:我想学LINUX内核,不知道买什么书
  • 内核学习求教!
  • 求教,Linux下键盘输入的所有数据都会经过Linux内核吗???
  • 求教!内核挂死在calibrating delay loop。。。。处!
  • 求教:关于内核物理地址和虚拟地址的问题
  • 求教,linux内核代码关于网络部分的浅析
  • 求教——编译内核(新手大派送)
  • 求教:一进程执行过程中被同一外部中断程序大量反复中断会不会引起内核栈溢出?
  • 求教,2.6.28内核中struct net 结构作用?
  • 求教linux2.6.31内核中ide与ata的问题
  • 紧急求教: LINUX 内核编译错误 !!!!!!!!!!
  • LINUX内核解读 求教
  • 看linux0.12内核遇到个很奇怪的赋值,求教用意.
  • 内核编译问题求教!
  • 问题求教:内核启动时卡在Freeing init memory:
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • 求教求教,shell问题...各位大哥,帮忙下
  • 400分求教: 求教一简单问题,现场给分
  • 高分求教:如何将JAVA文件(.class)制作成可执行文件(.exe),求教方法或工具推荐
  • 急!!求教linux命令的使用:统计出/bin目录中文件的个数,追加到文件filea的结尾
  • 求教:在UNIX中查找包含指定文字的文件名
  • 小白菜求教linux大鸟
  • JDK1.3.1初级问题求教
  • 初学者有问题求教!
  • 各路高手请进!高分求教,非常着急!
  • 高分求教的问题(关于SendMail设置)
  • 简单问题:从sun网站上当了个jdk1.4b3,bin后缀,求教怎么安装
  • 求教:知道当前时间,如何得到N天前的时间 ?
  • 求教:switch(condition)中的condition 必须为整型吗?
  • Linux远程访问的问题,高分求教:)
  • 求教:在Linux下如何做代理服务器?
  • 紧急求教!究竟Java里面有没有相当于C++的CPOINT的类阿?
  • 求教JAVA中XML解析问题
  • 50分求教,在JSP里如何将String转换成Double
  • 我刚装好,是不是需要配制环境变量?求教。
  • 400分求教JAVA皮肤的问题


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3