Socket 基礎程式設計(一)
阿新 • • 發佈:2019-01-22
一個通常意義上的Socket一般是分為Client與Server。
Server端需要實現:建立Socket-》繫結埠-》監聽埠-》處理建鏈請求-》資料互動-》關閉連結。
Client端相對簡單些:建立Socket-》發起TCP建鏈-》傳送資料請求-》資料互動-》關閉連結。
如下是各API函式對應的TCP業務動作:
Client 的connect對應的TCP中的SYN建聯請求,而伺服器的accept對應的就是SYN ACK。
當Server端Accept成功後,會新分配一個fd用於和客戶端做資料互動。
Close函式,則對應了四次揮手的動作。
如下是一簡單的Server與Client實現:
Server:
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SUCCESS 4
#define SERVERPORT 8888
#define SOCKMAXCONN 1024
int main()
{
char buffer[1024] = {0};
struct sockaddr_in client_socket_addr;
struct sockaddr_in server_socket_addr;
socklen_t length = sizeof(client_socket_addr);
//////////////////////////////////////////////////////////////////////////////
// struct sockaddr_in {
// __kernel_sa_family_t sin_family; /* Address family */
// __be16 sin_port; /* Port number */
// struct in_addr sin_addr; /* Internet address */
// unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) - sizeof(unsigned short int) - sizeof(struct in_addr)];
// };
///////////////////////////////////////////////////////////////////////////////
server_socket_addr.sin_family = AF_INET;
server_socket_addr.sin_port = htons(SERVERPORT);
server_socket_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//////////////////////////////////////////////////////////////////////////////
// Create a new socket of type TYPE in domain DOMAIN, using
// protocol PROTOCOL. If PROTOCOL is zero, one is chosen automatically.
// Returns a file descriptor for the new socket, or -1 for errors.
// extern int socket (int __domain, int __type, int __protocol) __THROW;
///////////////////////////////////////////////////////////////////////////////
int server_socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
///////////////////////////////////////////////////////////////////////////////
// Give the socket FD the local address ADDR (which is LEN bytes long).
// extern int bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
///////////////////////////////////////////////////////////////////////////////
if (SUCCESS != bind(server_socket_fd, (struct sockaddr *)&server_socket_addr, sizeof(server_socket_addr)))
{
perror ("Bind Socket Failed: ");
goto exit_half;
}
///////////////////////////////////////////////////////////////////////////////
// Prepare to accept connections on socket FD.
// N connection requests will be queued before further requests are refused.
// Returns 0 on success, -1 for errors.
// extern int listen (int __fd, int __n) __THROW;
///////////////////////////////////////////////////////////////////////////////
if(SUCCESS != listen(server_socket_fd, SOCKMAXCONN))
{
perror ("Listen Socket Failed: ");
goto exit_half;
}
///////////////////////////////////////////////////////////////////////////////
// A wait a connection on socket FD.
// When a connection arrives, open a new socket to communicate with it,
// set *ADDR (which is *ADDR_LEN bytes long) to the address of the connecting
// peer and *ADDR_LEN to the address's actual length, and return the
// new socket's descriptor, or -1 for errors.
// This function is a cancellation point and therefore not marked with __THROW.
// extern int accept (int __fd, __SOCKADDR_ARG __addr, socklen_t *__restrict __addr_len);
///////////////////////////////////////////////////////////////////////////////
int client_conn = accept(server_socket_fd, (struct sockaddr*)&client_socket_addr, &length);
if (-1 == client_conn)
{
perror ("Connect Socket Failed: ");
goto exit_half;
}
///////////////////////////////////////////////////////////////////////////////
// Read N bytes into BUF from socket FD.
// Returns the number read or -1 for errors.
// This function is a cancellation point and therefore not marked with __THROW.
// extern ssize_t recv (int __fd, void *__buf, size_t __n, int __flags);
///////////////////////////////////////////////////////////////////////////////
int client_len = recv(client_conn, buffer, sizeof(buffer), 0);
if (-1 == client_len)
{
perror ("Recv Socket Failed: ");
goto exit;
}
///////////////////////////////////////////////////////////////////////////////
// Send N bytes of BUF to socket FD. Returns the number sent or -1.
// This function is a cancellation point and therefore not marked with __THROW.
// extern ssize_t send (int __fd, const void *__buf, size_t __n, int __flags);
///////////////////////////////////////////////////////////////////////////////
if (-1 == send(client_conn, buffer, client_len, 0))
{
perror ("Send Socket Failed: ");
goto exit;
}
printf("Received Request: %s !\n", buffer);
goto exit;
exit:
//////////////////////////////////////////////////////////////////////////////
// Close the file descriptor FD.
// This function is a cancellation point and therefore not marked with
// __THROW.
// extern int close (int __fd);
//////////////////////////////////////////////////////////////////////////////
close(client_conn);
close(server_socket_fd);
return SUCCESS;
exit_half:
close(server_socket_fd);
return SUCCESS;
}
Client:
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SUCCESS 0
#define SERVERPORT 8888
int main()
{
char buffer[1024] = {0};
char *send_msg = "Hello World!";
struct sockaddr_in server_socket_addr = {0};
socklen_t server_addr_length = sizeof(server_socket_addr);
server_socket_addr.sin_family = AF_INET;
server_socket_addr.sin_port = htons(SERVERPORT);
if( inet_pton(AF_INET, "127.0.0.1", &server_socket_addr.sin_addr) <= 0)
{
perror ("Inet_pton Socket Failed: ");
goto exit;
}
//////////////////////////////////////////////////////////////////////////////
// Create a new socket of type TYPE in domain DOMAIN, using
// protocol PROTOCOL. If PROTOCOL is zero, one is chosen automatically.
// Returns a file descriptor for the new socket, or -1 for errors.
// extern int socket (int __domain, int __type, int __protocol) __THROW;
///////////////////////////////////////////////////////////////////////////////
int client_socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//////////////////////////////////////////////////////////////////////////////
// Open a connection on socket FD to peer at ADDR (which LEN bytes long).
// For connectionless socket types, just set the default address to send to
// and the only address from which to accept transmissions.
// Return 0 on success, -1 for errors.
// This function is a cancellation point and therefore not marked with __THROW.
// extern int connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len);
//////////////////////////////////////////////////////////////////////////////
if(SUCCESS != connect (client_socket_fd, (struct sockaddr*)&server_socket_addr, server_addr_length))
{
perror ("Connect Socket Failed: ");
goto exit;
}
///////////////////////////////////////////////////////////////////////////////
// Send N bytes of BUF to socket FD. Returns the number sent or -1.
// This function is a cancellation point and therefore not marked with __THROW.
// extern ssize_t send (int __fd, const void *__buf, size_t __n, int __flags);
///////////////////////////////////////////////////////////////////////////////
if (-1 == send(client_socket_fd, send_msg, strlen("Hello World!"), 0))
{
perror ("Send Socket Failed: ");
goto exit;
}
///////////////////////////////////////////////////////////////////////////////
// Read N bytes into BUF from socket FD.
// Returns the number read or -1 for errors.
// This function is a cancellation point and therefore not marked with __THROW.
// extern ssize_t recv (int __fd, void *__buf, size_t __n, int __flags);
///////////////////////////////////////////////////////////////////////////////
int client_len = recv(client_socket_fd, buffer, sizeof(buffer), 0);
if (-1 == client_len)
{
perror ("Recv Socket Failed: ");
goto exit;
}
printf("Received Response: %s !\n", buffer);
send(client_socket_fd, "BYE", strlen("BYE"), 0);
goto exit;
exit:
close(client_socket_fd);
return SUCCESS;
}