Linux网络编程(Linux网络编程第二版)

http://www.itjxue.com  2023-02-05 00:23  来源:未知  点击次数: 

面试时怎么教熟悉linux网络编程

不知你的水平处于哪个阶段,假如你是学嵌入式的,刚开始接触我建议你看华清远见写的《嵌入式Linux应用程序开发》虽然这本书上的好多是从后面我要说的书上抄的(嘿嘿,技术吗不能完全这样说)原因是:比较适合初学者,教材适合自己的才是王道,不能让小学生成天看牛津高级词典,一下子把人就吓住,刚开始要学的不要太多 不要指望一下子就明白全部,太厚的书,太全了 也太多,当然这个只是说你的水平在初级阶段

水平还行就看看国外的经典教材,当然是 W.Richard Stevens老人家写的经典3部(可惜他老人家现在走了 不能给我们再写经典 太可惜了)

1)Advanced Programming In The UNIX Environment 中文翻译名为《UNIX环境高级编程》译者:尤晋元,翻译的还行(在这里我要批评有些人成天给翻译的书挑刺 老说某某翻译的不好 甚至打骂,我说一句:有本事你看英文版行了,英语不行就不要叫,再说你自己看了多少,也许你只是成天跟着吆喝的人)

2)Unix Network Programing 中文翻译名为《UNIX网络编程》有两卷 清华大学,谁翻译的 呵呵 没注意

第一卷讲BSD Socket网络编程接口和另外一种网络编程接口的,不过现在一般都用BSD Socket,所以这本书只要看大约一半多就可以了。第二卷没有设计到网络的东西,主要讲进程间通讯和Posix线程。所以看了《UNIX环境高级编程》以后,就可以看它了,基本上系统的东西就由《UNIX环境高级编程》和《UNIX网络编程》vol2概括了。看过《UNIX网络编程》以后,您就会知道系统编程的绝大部分编程技巧,即使卷一是讲网络编程的。

3)《TCP/IP祥解》一共三卷,卷一讲协议,卷二讲实现,卷三讲编程应用。我没有怎么看过。,但是据说也很经典的,因为我没有时间看卷二,所以不便评价。

Windows和Linux下的网络编程方法的异同

Linux下的网络编程与Windows下采用底层的API类似,但是也有区别:区别一:Windows下需加上WSAStartup()函数区别二:关闭socket:Linux为close(),Windows为closesocket()windows下采用上层的API,一般有CSocket和CAsynSocket这两种类型的类这种情况以下socket函数一般的首字母大写。而底层的API不管是windows下的还是linux下的socket函数首字母都是小写的。

linux 网络编程 sendto 问题

sendto(经socket传送数据)

相关函数 send , sendmsg,recv , recvfrom , socket

表头文件 #include sys/types.h

#include sys/socket.h

定义函数 int sendto ( int s , const void * msg, int len, unsigned int flags, const

struct sockaddr * to , int tolen ) ;

函数说明 sendto() 用来将数据由指定的socket传给对方主机。参数s为已建好连线的socket,如果利用UDP协议则不需经过连线操作。参数msg指向欲连线的数据内容,参数flags 一般设0,详细描述请参考send()。参数to用来指定欲传送的网络地址,结构sockaddr请参考bind()。参数tolen为sockaddr的结果长度。

返回值 成功则返回实际传送出去的字符数,失败返回-1,错误原因存于errno 中。

错误代码 EBADF 参数s非法的socket处理代码。

EFAULT 参数中有一指针指向无法存取的内存空间。

WNOTSOCK canshu s为一文件描述词,非socket。

EINTR 被信号所中断。

EAGAIN 此动作会令进程阻断,但参数s的soket为补课阻断的。

ENOBUFS 系统的缓冲内存不足。

EINVAL 传给系统调用的参数不正确。

范例 #include sys/types.h

#include sys/socket.h

# include netinet.in.h

#include arpa.inet.h

#define PORT 2345 /*使用的port*/

main(){

int sockfd,len;

struct sockaddr_in addr;

char buffer[256];

/*建立socket*/

if(sockfd=socket (AF_INET,SOCK_DGRAM,0))0){

perror (“socket”);

exit(1);

}

/*填写sockaddr_in 结构*/

bzero ( addr, sizeof(addr) );

addr.sin_family=AF_INET;

addr.sin_port=htons(PORT);

addr.sin_addr=hton1(INADDR_ANY) ;

if (bind(sockfd, addr, sizeof(addr))0){

perror(“connect”);

exit(1);

}

while(1){

bezro(buffer,sizeof(buffer));

len = recvfrom(socket,buffer,sizeof(buffer), 0 , addr addr_len);

/*显示client端的网络地址*/

printf(“receive from %s\n “ , inet_ntoa( addr.sin_addr));

/*将字串返回给client端*/

sendto(sockfd,buffer,len,0,addr,addr_len);”

}

}

LINUX网络编程 connect被拒绝

一般经过创建套接字socket()绑定bind()以及listen()之后, 就可以调用 accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);判断是否有客户端发起链接请求, 不用accept()改用select()可以吗,select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout) 中哪个参数跟客户端有关?

linux网络编程中如何实现服务器端多个read()和客户端write( )

TCP通信的模式如下图,比较固定,对着图编代码就可以了:

服务器的main函数:

int main(int argc, char **argv)

{

?int listenfd, connfd;

?pid_t childpid;

?socklen_t clilen;

?struct sockaddr_in cliaddr, servaddr; //IPv4 address

?/*socket*/

?listenfd = socket(AF_INET, SOCK_STREAM, 0);//创建一个TCP的socket

?if (-1 == listenfd) {

? perror("socket erro.");

? return -1;

?}

?/*bind*/

?//首先初始化server的IP地址和端口,然后再与刚刚创建的socket绑定

?bzero(servaddr, sizeof(servaddr));

?servaddr.sin_family = AF_INET;//设置协议簇

?servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//绑定本机的网卡

?servaddr.sin_port = htons(1234);//绑定端口号,端口号可以随便取,大于1024就可以了

?if (-1 == bind(listenfd, (struct sockaddr *)servaddr, sizeof(servaddr))) {

? perror("bind error.");

? return -1;

?}

?/*listen*/

?//到这里已经有了一个绑定了IP地址和端口号的socket了,但是这个socket是个主动的socket,

?//而作为server需要的是一个等待别的接入的被动的socket,所以得调用listen将这个socket设置为监听状态

?//第二个参数表示服务器正在处理客户接入时的等待队列长度。

?if (-1 == listen(listenfd, 10)) {

? perror("listen error.");

? return -1;

?}

?while (1) {

? clilen = sizeof(cliaddr);

? //调用accept等待客户的接入,同时accept会用第二个参数返回客户的IP地址,

? //通过第三个参数返回IP地址的实际大小,同时这个参数也是个值-结构参数,也就是

? //在传递这个参数的时候,先给这个参数一个初始的值,然后函数中会根据具体的情况修改这个值,

? //所以这里传递的是指针。

? //当客户接入后,将返回一个成功和客服连接的socket描述符,通过读写这个socket即可实现和客户的通信了

? connfd = accept(listenfd, (struct sockaddr *)cliaddr, clilen);

? if (-1 == connfd) {

? ?if (EINTR == errno)

? ? continue;

? ?perror("accept error.");

? ?return -1;

? }

? //通过fock创建子进程来处理客户请求,这里只是显示客户的IP地址、端口号和发送的文字,

? //并将客户发送的文字回传给客户。

? if (0 == (childpid=fork())) {//fock返回0 说明是子进程

? ?//这里并没有关闭服务器的监听socket,只是将其引用计数减一,因为fork出来的子进程对父进程做了拷贝,

? ?//所以这个监听socket的引用计数将由1变成2,而内核只有在一个socket的引用计数变为0才回去关闭它

? ?close(listenfd);

? ?//通过和客户连接的socket和客户通信? ? ?

? ?str_echo(connfd, cliaddr);

? ?return 0;

? }

? //父进程将和客户连接的socket的引用计数减一,同样并没有关闭这个socket

? close(connfd);

?}

?return 0;

}

服务器处理客户请求:

#define BSIZE 100

void str_echo(int sockfd, struct sockaddr_in cliaddr)

{

?ssize_t n;

?char buf[BSIZE];

?

?while ((n=read(sockfd, buf, BSIZE))) {//读取客户发送的信息

? buf[n] = '\0';

? printf("IP: %s, PORT: %d: %s\n", \

? ? inet_ntoa(cliaddr), ntohs(cliaddr.sin_port), buf); //输出信息

? n_write(sockfd, buf, n);//将受到的信息发送回客户,n_write的实现下面给出

?}

}

客户端程序相对简单:

int main(int argc, char **argv)

{

?int sockfd;

?struct sockaddr_in servaddr;

?

?if (2 != argc) {

? printf("usage: ./client 127.0.0.1");//

? return -1;

?}

?/*socket*/

?sockfd = socket(AF_INET, SOCK_STREAM, 0);?//创建一个socket

?if (-1 == sockfd) {

? perror("socket error.");

? return -1;

?}

?/*connect*/

?//首先初始化要连接的服务器的IP地址和端口号,然后调用connect去连接这个服务器

?bzero(servaddr, sizeof(servaddr));

?servaddr.sin_family = AF_INET;

?servaddr.sin_port = htons(1234);

?inet_pton(AF_INET, argv[1], servaddr.sin_addr);

?if (-1 == connect(sockfd, (struct sockaddr *)servaddr, sizeof(servaddr))) {

? perror("connect error.");

? return -1;

?}

?//连接成功后就可以通过这个socket来和服务器通信了

?str_cli(stdin, sockfd);

return 0;

}

n_write 和 readline

/*write n bytes to fd*/

ssize_t n_write (int fd, void *buf, size_t n)

{

?size_t nleft = n;

?ssize_t nwriten;

?char *bufp = buf;

while (nleft 0) {

? if ((nwriten = write (fd, bufp, nleft)) = 0) {

? ?if (EINTR == errno)

? ? nwriten = 0;

? ?else

? ? return -1;

? }

nleft -= nwriten;

? bufp += nwriten;

?}

return n;

}

/*read line from fd*/

ssize_t readline (int fd, void *buf, size_t maxlen)

{

?ssize_t n, rc;

?char c, *bufp;

bufp = buf;

?for (n = 1; n maxlen; n ++) {

again:

? if (1 == (rc = read (fd, c, 1))) {

? ?*bufp ++ = c;

? ?if ('\n' == c)

? ? break;? /*newline is stored*/

? } else if (rc == 0) {

? ?*bufp = 0;

? ?return (n - 1);? /*EOF, n-1 bytes were read*/

? } else {

? ?if (EINTR == errno)?/*interrupt*/

? ? goto again;

? ?return -1;? /*Erro, set the errno by read ()*/

? }

?}

?*bufp = 0;

?return n;

}

运行结果:

因为客户端没有指定IP地址和端口,所以其IP和端口都是内核随机分配的。

linux网络编程中阻塞和非阻塞socket的区别

对于阻塞的socket,当socket的接收缓冲区中没有数据时,read调用会一直阻塞住,直到有数据到来才返

回。当socket缓冲区中的数据量小于期望读取的数据量时,返回实际读取的字节数。当sockt的接收缓冲

区中的数据大于期望读取的字节数时,读取期望读取的字节数,返回实际读取的长度。

对于非阻塞socket而言,socket的接收缓冲区中有没有数据,read调用都会立刻返回。接收缓冲区中有

数据时,与阻塞socket有数据的情况是一样的,如果接收缓冲区中没有数据,则返回错误号为

EWOULDBLOCK,

表示该操作本来应该阻塞的,但是由于本socket为非阻塞的socket,因此立刻返回,遇到这样的情况,可

以在下次接着去尝试读取。如果返回值是其它负值,则表明读取错误。

因此,非阻塞的rea调用一般这样写:

if ((nread = read(sock_fd, buffer, len)) 0)

{

if (errno == EWOULDBLOCK)

{

return 0; //表示没有读到数据

}else return -1; //表示读取失败

}else return nread;读到数据长度

(责任编辑:IT教学网)

更多

推荐软件水平考试文章