A C language / hi hello and simple chat program to track and analyze system call

Introduction socket programming

Socket Interface is a TCP / IP network API, Socket Interface defines a number of functions or routines, can use to develop applications on a TCP / IP network.

Socket Interface designer was first interface on the Unix operating system inside. If you know the input and output of a Unix system, then it is easy to understand Socket up. Network Socket is a special data transmission the I / O, Socket also a file descriptor. Socket also has a similar function to open file call Socket (), the function returns an integer Socket descriptor, then the connection establishment, data transfer and other operations is through the Socket achieved.

Commonly used Socket There are two types: streaming Socket ( SOCK_STREAM) and Datagram Socket ( SOCK_DGRAM). Streaming is a connection-oriented Socket, directed to the connection-oriented TCP service application; Datagram Socket is a connectionless Socket, corresponding to the connectionless UDP service application.

client / server communication model

In client / server mode, we will ask the party called customer service ( Client), will offer a service called party server ( Server).

A service normally listens at a well-known program address the request for service, that service process has been dormant until a customer service made this address connection requests. At this moment, the service program is "wake up" and provide services to customers - an appropriate response to customer requests.

Sockets 

A socket is a communication endpoint, which is Socket object is sent to the application over a network or receive data packets.

Socket has a type associated with running processes linked, and can have a name.

Sockets generally using the same Internet protocol suite to exchange data other sockets "communication Domains".

 

 

Programming process stream socket

Client

1. Create a socket

client_sockfd=socket(PF_INET,SOCK_STREAM,0)

Function to create a socket with the socket, the socket descriptor Returns

 

2. Define the server address

REMOTE_ADDR the sockaddr_in struct; // server network address structure Memset (& REMOTE_ADDR, 0, the sizeof (REMOTE_ADDR)); // Initialize data - clears 
remote_addr.sin_family = AF_INET; // set the IP communication 
remote_addr.sin_addr.s_addr = inet_addr ( " 127.0.0.1 " ); // server IP address 
remote_addr.sin_port = htons ( 8000 ); // server port

 

3. The connection to the server

connect(client_sockfd,(struct sockaddr *)&remote_addr,sizeof(struct sockaddr)

Address structure type is used tcp / ip application is socketsddr_in, the socket and the socket address type is applied socketaddr, it is necessary to be cast.

 

4. The data transmission and reception

len=send(client_sockfd,buf,strlen(buf),0);
len=recv(client_sockfd,buf,BUFSIZ,0);

The length of the known data when data is transmitted, calculated using strlen (buf); and the received data length is not known, it must be set to the maximum length of the array receiving definition data is received, and then receiving the return value is determined by the function the actual size of the array.

5. Close the socket

Close (client_sockfd); // Close the socket

No data can be sent off to the socket

 

Service-Terminal

1. Create a socket, defined its own address

int server_sockfd=socket(PF_INET,SOCK_STREAM,0);//服务器端套接字
struct sockaddr_in my_addr; //服务器网络地址结构体 memset(&my_addr,0,sizeof(my_addr)); //数据初始化--清零 my_addr.sin_family=AF_INET; //设置为IP通信 my_addr.sin_addr.s_addr=INADDR_ANY;//服务器IP地址--允许连接到所有本地地址上 my_addr.sin_port=htons(8000); //服务器端口号

 

2.将套接字与地址绑定

 

bind(server_sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr)

 

3.监听是否有客户请求

listen(server_sockfd,5);

 

4接受客户端请求

client_sockfd=accept(server_sockfd,(struct sockaddr *)&remote_addr,&sin_size)

accept函数返回新的连接的套接字描述符。为每个新的连接请求创建了一个新的套接字,服务器只对新的连接使用该套接字,原来的监听套接字接受其他的连接请求。新的连接上传输数据使用新的套接字,使用完毕,服务器将关闭这个套接字。

 

5.接收并发送数据

while((len=recv(client_sockfd,buf,BUFSIZ,0))>0)
    {
        buf[len]='\0';
        printf("recieved:%s\n",buf);
                printf("Enter string to send: ");
                scanf("%s",buf);
        if(send(client_sockfd,buf,strlen(buf),0)<0)
        {
            perror("write");
            return 1;
        }
    }

 

6关闭套接字

close(client_sockfd);
close(server_sockfd);

 

实现代码

客户端

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <sys/types.h>
 4 #include <sys/socket.h>
 5 #include <netinet/in.h>
 6 #include <arpa/inet.h>
 7 #include <unistd.h> 
 8 
 9 int main(int argc, char *argv[])
10 {
11     int client_sockfd;
12     int len;
13     struct sockaddr_in remote_addr; //服务器端网络地址结构体
14     char buf[BUFSIZ];  //数据传送的缓冲区
15     memset(&remote_addr,0,sizeof(remote_addr)); //数据初始化--清零
16     remote_addr.sin_family=AF_INET; //设置为IP通信
17     remote_addr.sin_addr.s_addr=inet_addr("127.0.0.1");//服务器IP地址
18     remote_addr.sin_port=htons(8000); //服务器端口号
19     
20     /*创建客户端套接字--IPv4协议,面向连接通信,TCP协议*/
21     if((client_sockfd=socket(PF_INET,SOCK_STREAM,0))<0)
22     {
23         perror("socket");
24         return 1;
25     }
26     
27     /*将套接字绑定到服务器的网络地址上*/
28     if(connect(client_sockfd,(struct sockaddr *)&remote_addr,sizeof(struct sockaddr))<0)
29     {
30         perror("connect");
31         return 1;
32     }
33     printf("connected to server\n");
34     len=recv(client_sockfd,buf,BUFSIZ,0);//接收服务器端信息
35          buf[len]='\0';
36     printf("%s",buf); //打印服务器端信息
37     
38     /*循环的发送接收信息并打印接收信息--recv返回接收到的字节数,send返回发送的字节数*/
39     while(1)
40     {
41         printf("Enter string to send:");
42         scanf("%s",buf);
43         if(!strcmp(buf,"quit"))
44             break;
45         len=send(client_sockfd,buf,strlen(buf),0);
46         len=recv(client_sockfd,buf,BUFSIZ,0);
47         buf[len]='\0';
48         printf("received:%s\n",buf);
49     }
50     close(client_sockfd);//关闭套接字
51     return 0;
52 }

 

服务器端

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <sys/types.h>
 4 #include <sys/socket.h>
 5 #include <netinet/in.h>
 6 #include <arpa/inet.h>
 7 #include <unistd.h> 
 8 
 9 int main(int argc, char *argv[])
10 {
11     int server_sockfd;//服务器端套接字
12     int client_sockfd;//客户端套接字
13     int len;
14     struct sockaddr_in my_addr;   //服务器网络地址结构体
15     struct sockaddr_in remote_addr; //客户端网络地址结构体
16     int sin_size;
17     char buf[BUFSIZ];  //数据传送的缓冲区
18     memset(&my_addr,0,sizeof(my_addr)); //数据初始化--清零
19     my_addr.sin_family=AF_INET; //设置为IP通信
20     my_addr.sin_addr.s_addr=INADDR_ANY;//服务器IP地址--允许连接到所有本地地址上
21     my_addr.sin_port=htons(8000); //服务器端口号
22     
23     /*创建服务器端套接字--IPv4协议,面向连接通信,TCP协议*/
24     if((server_sockfd=socket(PF_INET,SOCK_STREAM,0))<0)
25     {  
26         perror("socket");
27         return 1;
28     }
29  
30         /*将套接字绑定到服务器的网络地址上*/
31     if (bind(server_sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))<0)
32     {
33         perror("bind");
34         return 1;
35     }
36     
37     /*监听连接请求--监听队列长度为5*/
38     listen(server_sockfd,5);
39     
40     sin_size=sizeof(struct sockaddr_in);
41     
42     /*等待客户端连接请求到达*/
43     if((client_sockfd=accept(server_sockfd,(struct sockaddr *)&remote_addr,&sin_size))<0)
44     {
45         perror("accept");
46         return 1;
47     }
48     printf("accept client %s\n",inet_ntoa(remote_addr.sin_addr));
49     len=send(client_sockfd,"Welcome to my server\n",21,0);//发送欢迎信息
50     
51     /*接收客户端的数据并将其发送给客户端--recv返回接收到的字节数,send返回发送的字节数*/
52     while((len=recv(client_sockfd,buf,BUFSIZ,0))>0)
53     {
54         buf[len]='\0';
55         printf("recieved:%s\n",buf);
56                 printf("Enter string to send: ");
57                 scanf("%s",buf);
58         if(send(client_sockfd,buf,strlen(buf),0)<0)
59         {
60             perror("write");
61             return 1;
62         }
63     }
64     close(client_sockfd);
65     close(server_sockfd);
66     return 0;
67 }

 

 运行结果

 

跟踪分析到系统调用

当用户进程使用socket API 的时候,会产生向量为0x80的编程异常,系统执行系统调用。

进程传递系统调用号到寄存器eax,指明需要哪个系统调用,同时会将系统调用需要的参数存入相关寄存器。

系统调用处理函数system_call是Linux中所有系统调用的入口点,通过进程存在eax寄存器中的系统调用号决定调用哪个系统调用,而所有的socket系统调用的总入口时sys_socketcall()。

 

对如下代码跟踪分析

int socket(int domain, int type, int protocol);

 用户进程将sys_socket()的系统调用号198存入eax中,并将socket()函数中的三个参数分别存入ebx,ecx,edx寄存器,产生一个0x80的编程异常。系统调用处理函数根据系统调用号,执行sys_socket()。

sys_socket在内核中的源码为:

SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
{
    int retval;
    struct socket *sock;
    int flags;

...
    retval = sock_create(family, type, protocol, &sock);
    if (retval < 0)
        goto out;

    retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
    if (retval < 0)
        goto out_release;

out:
    /* It may be already another descriptor 8) Not kernel problem. */
    return retval;

out_release:
    sock_release(sock);
    return retval;
}

可以看到,socket函数主要由sock_createsock_map_fd这两个函数完成。

sock_create函数用于创建socket。sock_create() 实际调用的是 __sock_create(),其中比较重要的是sock_alloc()pf->create()两个函数。

sock_map_fd函数用于得到一个文件号。这个函数主要有两个部分,一个是创建file文件结构,fd文件描述符,另一部分是将file文件结构和fd文件描述符关联,同时将上一步返回的socket也一起绑定,形成一个完整的逻辑。

socket系统调用的操作概述为:首先在内核生成一个socket_alloc 和tcp_sock类型的对象,其中sock_alloc对象中的socket和tcp_sock对象的sock绑定,sock_alloc对象中的inode和file类型对象绑定。然后将分配的文件描述符fd和file对象关联,最后将这个文件描述符fd返回给用户使用。

 

 

 

 

 

 

 

 

 

 

 

 

Guess you like

Origin www.cnblogs.com/qfdzztt/p/12012056.html
Recommended