Linux Socket chat rooms under implementation

One. Principle Analysis:

①: socket programming introduction

This experiment implemented by programming socket, Socket interface is a TCP / IP network of the API, Socket interface defines a number of functions or routines, you can use to develop applications on the TCP / IP network. Socket complex TCP / IP protocol suite is hidden behind the Socket interface for users, a simple interface is all set, let Socket to organize data in order to comply with the specified protocol. There are two common types Socket: Socket stream (SOCK_STREAM) and Datagram Socket (SOCK_DGRAM). Streaming is a connection-oriented Socket for service application in connection-oriented TCP; Datagram Socket Socket is a connectionless, corresponding to UDP is connectionless services.

Obviously, this experiment using a socket connection for streaming.

In different operating systems, socket is also provided different:

Socket different operating systems

Windows Socket (Winsock)

Linux Socket (BSD Socket)

 

Socket socket meanings:

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

2. The socket has a type, and associated running processes, and can have a name

3. The socket generally using the same Internet protocol suite to exchange data other sockets "communication domain" in

 

 

②: Client / server communication model introduced

In this experiment, Client / server communication model as a specific configuration of the experiment.

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.

The client and server processes run as follows:

 

 

 

In the experiment a request, the client is: the server section transmits to the source string is not treated, the server for processing requirements

The server's response is: distributed client-treated string

 

③: the connection establishment process and transfer data between the client and the server using socket programming

Flowchart is given:

 

 

 

Use of all aspects of the code will explain later in the code analysis

 

④: multi-threaded programming under linux c ++ is based on

Multithreading is a specialized form of multi-tasking, multi-tasking allows let the computer run two or more programs. In general, two types of multitasking: process-based and thread-based.

Multi-tasking is a process-based program concurrently.

* Multi-tasking threads are executed concurrently fragment of the same program.

 

Multi-threaded program contains two or more parts that can run concurrently. Each part of such a program is called threads, each defining a single execution path.

Create a thread

The following program, you can use it to create a POSIX threads:

    #include <pthread.h>

    pthread_create (thread, attr, start_routine, arg)

Here, pthread_create creates a new thread and make it executable. The following is a description of the parameters:

 

When you create a thread successfully, the function returns 0, if the return value of 0 indicates that failed to create thread.

Terminate the thread

Use the following procedure, you can use it to terminate a POSIX threads:

    #include <pthread.h>

    pthread_exit (status)

Here, pthread_exit used to explicitly exit a thread. Typically, pthread_exit () function is called when there is no need to continue the work after the completion of the thread.

If the main () is the thread that it created before the end, and () to exit through pthread_exit, the other threads will continue to execute. Otherwise, they will () is automatically terminated at the end of main.

 

two. experiment process

In this experiment, we use a Linux system as the experimental vehicle. So do not use additional inspection system protocol stack installation. Therefore, the general process is:

1. Create client.c documents and files are sever.c

2. Use the socket () function creates the server side communication socket

3. Use the bind () socket with the server address of the function will create bindings

4. The server uses listen () function so that the socket is ready to receive a connection request server preparation connect function using the client issuing a request to establish connection to the server (before the call can not bind () port number, is done automatically by the system)

5. Use accept () receives the connection request from the client by the connect () function issued

6. After the connection is established according to the connection request using a send () function to send data, or use the recv () function receives data

7. Preparation handler, so that the service request from the client side processing section, and in response

8. Use Closet () function to close the socket (can first shutdown () function to close the read-write channel)

9. Gcc c formed executable file

10. Run the executable to see experimental results:

 

Open multi-threaded server

 

 

 

 

Achieve information exchange

 

 

 

 

Three: Key code analysis:

Sever end after establishing a connection, open a new thread operations:

 

int session_fd = accept(server_socket_fd, (struct sockaddr*)&client_addr, &client_addr_length);
if(session_fd < 0)
{
perror("Server Accept Failed:");
// break;
}
char client_addr_res[20];
//char *ptr=inet_ntop(AF_INET, &client_addr.sin_addr, client_addr_res, strlen(client_addr_res));
printf("Get Connected with Client:%s ,the port is :%d Opening a new Thread...\n",inet_ntoa(client_addr.sin_addr),client_addr.sin_port);
pthread_t thread_id;
if (pthread_create(&thread_id, NULL, (void *)(&Data_handle), (void *)(&session_fd)) == -1)
{
fprintf(stderr, "pthread_create error!\n");
break; //break while loop
}


}

 

在子线程中进行数据处理,即接受客户端发来的消息,然后验证是否是“hi”信息,并发送回应

 

static void Data_handle(void * fd)
{
int session_fd = *((int *)fd);
// recv函数通过描述字读取数据到字节流,并存储到地址字符串
char buffer[BUFFER_SIZE];
bzero(buffer, BUFFER_SIZE);
if (recv(session_fd, buffer, BUFFER_SIZE, 0) < 0)
{
perror("Server Recieve Data Failed:");
}

if(strcmp(buffer,"hi")==0)
{
bzero(buffer, BUFFER_SIZE);

strcpy(buffer, "hello");

if (send(session_fd, buffer, BUFFER_SIZE, 0) < 0)
{
printf("Send Failed./n");
}

}

else
{

bzero(buffer, BUFFER_SIZE);

strcpy(buffer, "i do not understand");

if (send(session_fd, buffer,BUFFER_SIZE , 0) < 0)
{
printf("Send Failed./n");
}

}

close(session_fd);
pthread_exit(NULL); //terminate calling thread!
}

后面附上客户端和服务端的代码

client.c

#include<netinet/in.h>  

#include<sys/types.h>  

#include<sys/socket.h>   

#include<stdio.h>  

#include<stdlib.h>   

#include<string.h> 



#define SERVER_PORT 8000   

#define BUFFER_SIZE 1024   



void find_file_name(const char *name,const char *path);

int main()

{

	struct sockaddr_in client_addr;

	bzero(&client_addr, sizeof(client_addr));

	client_addr.sin_family = AF_INET;

	client_addr.sin_addr.s_addr = htons(INADDR_ANY);

	client_addr.sin_port = htons(0);

  

	int client_socket_fd = socket(AF_INET, SOCK_STREAM, 0);

	if (client_socket_fd < 0)

	{

		perror("Create Socket Failed:");

		exit(1);

	}



	if (-1 == (bind(client_socket_fd, (struct sockaddr*)&client_addr, sizeof(client_addr))))

	{

		perror("Client Bind Failed:");

		exit(1);

	}

//////////////////////////////////////////////////////////////////////////////////////////////////////

	// 声明一个服务器端的socket地址结构,并用服务器那边的IP地址及端口对其进行初始化,用于后面的连接   

	struct sockaddr_in server_addr;

	bzero(&server_addr, sizeof(server_addr));

	server_addr.sin_family = AF_INET;

	//将点分十进制串转换成网络字节序二进制值,此函数对IPv4地址和IPv6地址都能处理。

	//	第一个参数可以是AF_INET或AF_INET6:

	//	第二个参数是一个指向点分十进制串的指针:

	//	第三个参数是一个指向转换后的网络字节序的二进制值的指针。

	if (inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) == 0)

	{

		perror("Server IP Address Error:");

		exit(1);

	}



	server_addr.sin_port = htons(SERVER_PORT);

	socklen_t server_addr_length = sizeof(server_addr);



	// int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 

	// sockfd:第一个参数即为客户端的socket描述字

	//	addr:当前客户端的本地地址,是一个 struct sockaddr_un 类型的变量, 在不同主机中是struct sockaddr_in 类型的变量,

	//	addrlen:表示本地地址的字节长度

	//	返回值 : 成功标志

	if (connect(client_socket_fd, (struct sockaddr*)&server_addr, server_addr_length) < 0)

	{

		perror("Can Not Connect To Server IP:");

		exit(0);

	}

   

        char buffer[BUFFER_SIZE];

	bzero(buffer, BUFFER_SIZE);

          

	printf("Input the hello on Sever:\t");

	scanf("%s", buffer);



	

	

	//ssize_t send(int sockfd, const void *buf, size_t len, int flags);

	//socket:如果是服务端则是accpet()函数的返回值,客户端是connect()函数中的第一个参数

	// buffer:写入或者读取的数据

	// len:写入或者读取的数据的大小

	if (send(client_socket_fd, buffer, BUFFER_SIZE, 0) < 0)

	{

		perror("Send Failed:");

		exit(1);

	}





	while (recv(client_socket_fd, buffer, BUFFER_SIZE, 0)> 0)

	{

		        

			printf("from server %s \n", buffer);

                        if(strcmp(buffer,"hello")==0)
                      { 
                        printf("get the hello from Sever:\n");
                        

			break;}

		

	}



	

	close(client_socket_fd);

	return 0;

}

 

server.c

#include<stdlib.h>

#include<pthread.h>

#include<netinet/in.h> 

#include<sys/types.h>   

#include<sys/socket.h>  

#include<stdio.h>    

#include<stdlib.h>  

#include<string.h>     

#include<arpa/inet.h>



#define SERVER_PORT 8000   

#define LENGTH_OF_LISTEN_QUEUE 20   

#define BUFFER_SIZE 1024   

#define FILE_NAME_MAX_SIZE 512   

static void Data_handle(void * sock_fd);

int main(void)   

{   



////////////////////////////////////////////////////////////////////////////////////////////////////////////

  // 声明并初始化一个服务器端的socket地址结构,sockaddr_in是internet环境下套接字的地址形式

  //sockaddr_in(在netinet / in.h中定义):

  //    struct  sockaddr_in {

  //    short  int  sin_family;                      /* Address family */

  //    unsigned  short  int  sin_port;       /* Port number */

  //    struct  in_addr  sin_addr;              /* Internet address */

  //    unsigned  char  sin_zero[8];         /* Same size as struct sockaddr */

  //};

  //struct  in_addr {unsigned  long  s_addr;};

  struct sockaddr_in server_addr;   

  bzero(&server_addr, sizeof(server_addr)); 

  //Sa_family: 是地址家族,也成作,协议族,一般都是"AF_XXX"的形式,常用的有

  //AF_INET  Arpa(TCP / IP) 网络通信协议

  //AF_UNIX  UNIX 域协议(文件系统套接字)

  //AF_ISO    ISO标准协议

  //AF_NS    施乐网络体统协议

  //AF_IPX  Novell IPX 协议

  //AF_APPLETALK   Appletalk DDS

  server_addr.sin_family = AF_INET;   



  //htons是将整型变量从主机字节顺序转变成网络字节顺序, 就是整数在地址空间存储方式变为高位字节存放在内存的低地址处。

  //INADDR_ANY:0.0.0.0,泛指本机的意思,也就是表示本机的所有IP,监听本机所有网卡

  server_addr.sin_addr.s_addr = htons(INADDR_ANY);   

  server_addr.sin_port = htons(SERVER_PORT);   

  ////////////////////////////////////////////////////////////////////////////////////////////////////////////



  // 创建socket,若成功,返回socket描述符   

  //1、domain:即协议域,又称为协议族(family)。AF_INET:TCP/IP协议簇

  //2、type:指定socket类型。SOCK_STREAM(常用)字节流套接字

  //3、protocol:故名思意,就是指定协议。0:IPPROTO_TCP TCP传输协议 

  int server_socket_fd = socket(PF_INET, SOCK_STREAM, 0);   

  if(server_socket_fd < 0)   

  {   

    perror("Create Socket Failed:");   

    exit(1);   

  }   

 

  //int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);

  //sock:将要被设置或者获取选项的套接字。level:选项所在的协议层。

  //optname:需要访问的选项名。optval:对于getsockopt(),指向返回选项值的缓冲。optlen:作为入口参数时,选项值的最大长度。

  // 令SO_REUSEADD==true 允许套接口和一个已在使用中的地址捆绑(参见bind())。

  int opt = 1;

  setsockopt(server_socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));   

    

  //bind绑定socket和socket地址结构   

  //三个参数为:socket描述符、协议地址、地址的长度

  if(-1 == (bind(server_socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr))))   

  {   

    perror("Server Bind Failed:");   

    exit(1);   

  }   

  //sockfd:第一个参数即为要监听的socket描述符

  //backlog : 第二个参数为相应socket可以排队的最大连接个数

  //socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。

  if(-1 == (listen(server_socket_fd, LENGTH_OF_LISTEN_QUEUE)))   

  {   

    perror("Server Listen Failed:");   

    exit(1);   

  }   

  printf("Socket Init Successful!  Begin to listen!\n");

///////////////////////////////////////////////////////////////////////////////////////////////////////////



  while(1)   

  {   

    // 定义客户端的socket地址结构   

    struct sockaddr_in client_addr;   

    socklen_t client_addr_length = sizeof(client_addr);   

    

    //int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

    //sockfd:第一个参数为服务器的socket描述符

    //addr:,第二个参数为指向struct sockaddr *的指针,用于返回客户端的协议地址

    //addrlen:第三个参数为协议地址的长度

    //返回值 : 如果accpet成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的TCP连接。



    // 接受连接请求,返回一个新的socket(描述符),这个新socket用于同连接的客户端通信   

    // accept函数会把连接到的客户端信息写到client_addr中   

    int session_fd = accept(server_socket_fd, (struct sockaddr*)&client_addr, &client_addr_length);   

    if(session_fd < 0)   

    {   

      perror("Server Accept Failed:");   

    //  break;   

    }   

    char client_addr_res[20];

    //char *ptr=inet_ntop(AF_INET, &client_addr.sin_addr, client_addr_res, strlen(client_addr_res));

    printf("Get Connected with Client:%s ,the port is :%d Opening a new Thread...\n",inet_ntoa(client_addr.sin_addr),client_addr.sin_port);

    pthread_t thread_id;

    if (pthread_create(&thread_id, NULL, (void *)(&Data_handle), (void *)(&session_fd)) == -1)

    {

        fprintf(stderr, "pthread_create error!\n");

        break;                                  //break while loop

    }

    

 

  }   

  // 关闭监听用的socket   

  close(server_socket_fd);   

  return 0;   

}   



static void Data_handle(void * fd)

{

    int session_fd = *((int *)fd);

    // recv函数通过描述字读取数据到字节流,并存储到地址字符串

    char buffer[BUFFER_SIZE];

    bzero(buffer, BUFFER_SIZE);

    if (recv(session_fd, buffer, BUFFER_SIZE, 0) < 0)

    {

        perror("Server Recieve Data Failed:");

    }

    

    if(strcmp(buffer,"hi")==0)

        {

               bzero(buffer, BUFFER_SIZE);



               strcpy(buffer, "hello");

     

             if (send(session_fd, buffer, BUFFER_SIZE, 0) < 0)

            {

                printf("Send Failed./n");

            }



                       }



        else 

         {



               bzero(buffer, BUFFER_SIZE);



               strcpy(buffer, "i do not understand");



             if (send(session_fd, buffer,BUFFER_SIZE , 0) < 0)

            {

                printf("Send Failed./n");

            }



                       }



        close(session_fd);

    pthread_exit(NULL);   //terminate calling thread!

}

 

 

 

 

 

 

 

 

Guess you like

Origin www.cnblogs.com/hambug/p/12000706.html