网络协议栈学习(一)socket通信实例

时间:2023-01-14 14:34:05

网络协议栈学习(一)socket通信实例

该实例摘自《linux网络编程》(宋敬彬,孙海滨等著)。

  例子分为服务器端和客户端,客户端连接服务器后从标准输入读取输入的字符串,发送给服务器;服务器接收到字符串后,发送给服务器;服务器接收到字符串后统计字符串的长度,然后将该值传给客户端;客户端将接收到的信息打印到标准输出。

一、服务器端代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h> #define PORT 8888
#define BACKLOG 2
#define LENGTH 1024 void process_conn_server(int s)
{
int size = ;
char buffer[LENGTH]; for(;;){
size = read(s, buffer, LENGTH); if(size == )
return;
sprintf(buffer, "%d bytes altogether\n", size);
write(s, buffer, strlen(buffer)+);
}
}
int main(int argc, char**argv)
{
int ss, sc;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
int err;
pid_t pid; ss = socket(AF_INET, SOCK_STREAM, );
if(ss < ){
printf("socket error\n");
return -;
} bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(PORT); err = bind(ss, (struct sockaddr*)&server_addr, sizeof(server_addr));
if(err < ){
printf("bind error\n");
return -;
} err = listen(ss, BACKLOG);
if(err < ){
printf("listen error\n");
return -;
} for(;;){
int addrlen = sizeof(struct sockaddr);
sc = accept(ss, (struct sockaddr*)&client_addr, &addrlen);
if(sc < )
continue; pid = fork();
if(pid == ){
close(ss);
process_conn_server(sc);
}
else
close(sc);
}
return ;
}

  为了方便处理,服务器端在接收到客户端的请求后会fork一个新的进程来处理。函数fork出来的进程集成了父进程的属性,泪如套接字描述符,在子进程和父进程中都各有一套。

  为了防止误操作,在父进程中关闭了客户端的套接字描述符,在子进程中关闭了服务器端的套接字描述符。一个进程中套接字的关闭不会造成套接字的真正关闭,只有当所有使用这些套接字的进程都关闭该套接字描述符,linux内核才释放它们。

二、客户端代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h> #define PORT 8888
#define LENGTH 1024 void process_conn_client(int s)
{
int size = ;
char buffer[LENGTH]; for(;;){
size = read(, buffer, LENGTH);
if(size > ){
write(s, buffer, size);
size = read(s, buffer, LENGTH);
write(, buffer, size);
} }
}
int main(int argc, char**argv)
{
int s;
struct sockaddr_in server_addr;
int err; s = socket(AF_INET, SOCK_STREAM, );
if(s < ){
printf("socket error\n");
return -;
} bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(PORT); connect(s, (struct sockaddr*)&server_addr, sizeof(struct sockaddr));
process_conn_client(s);
close(s);
return ;
}

下面将结合该例子与网络协议栈源码学习如下问题:

1、socket 本质

2、socket 数据发送机制

3、socket 数据接收机制