套接字基礎知識
POSIX API 中有四種型別的套接字:TCP,UDP,UNIX 和(可選)RAW。Unix 域套接字可能像流套接字或資料包套接字一樣。
一些端點型別:
struct sockaddr
- 通用端點型別。通常,其他具體端點型別僅在 posix 呼叫中轉換為此型別。struct sockaddr_in
- IPv4 端點
struct sockaddr_in {
sa_family_t sin_family;
in_port_t sin_port; /* Port number. */
struct in_addr sin_addr; /* Internet address. */
};
struct in_addr {
in_addr_t s_addr;
};
struct sockaddr_in6
- IPv6 端點
struct sockaddr_in6 {
sa_family_t sin6_family;
in_port_t sin6_port; /* Transport layer port # */
uint32_t sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id; /* IPv6 scope-id */
};
struct sockaddr_un
。
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[108]; /* pathname */
};
整個計劃
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#define DESIRED_ADDRESS "127.0.0.1"
#define DESIRED_PORT 3500
#define BUFSIZE 512
int main()
{
// ADDRESS PART
// MAIN PART
close(sock);
return EXIT_SUCCESS;
}
建立 IPv4 端點
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = htons(DESIRED_PORT); /*converts short to
short with network byte order*/
addr.sin_addr.s_addr = inet_addr(DESIRED_ADDRESS);
TCP 伺服器片段
int sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == -1) {
perror("Socket creation error");
return EXIT_FAILURE;
}
if (bind(sock, (struct sockaddr*) &addr, sizeof(addr)) == -1) {
perror("Bind error");
close(sock);
return EXIT_FAILURE;
}
if (listen(sock, 1/*length of connections queue*/) == -1) {
perror("Listen error");
close(sock);
return EXIT_FAILURE;
}
socklen_t socklen = sizeof addr;
int client_sock = accept(sock, &addr, &socklen); /* 2nd and 3rd argument may be NULL. */
if (client_sock == -1) {
perror("Accept error");
close(sock);
return EXIT_FAILURE;
}
printf("Client with IP %s connected\n", inet_ntoa(addr.sin_addr));
char buf[BUFSIZE];
if (send(sock, "hello", 5, 0) == -1) {
perror("Send error");
close(client_sock);
close(sock);
return EXIT_FAILURE;
}
ssize_t readden = recv(sock, buf, BUFSIZE, 0);
if (readden < 0) {
perror("Receive error");
close(client_sock);
close(sock);
return EXIT_FAILURE;
}
else if (readden == 0) {
fprintf(stderr, "Client orderly shut down the connection.\n");
}
else {readden > 0) {
if (readden < BUFSIZE)
{
fprintf(stderr, "Received less bytes (%zd) then requested (%d).\n",
readden, BUFSIZE);
}
write (STDOUT_FILENO, buf, readden);
}
TCP 客戶端程式碼段
int sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == -1) {
perror("Socket creation error");
return EXIT_FAILURE;
}
if (connect(sock, (struct sockaddr*) &addr, sizeof(addr)) == -1) {
perror("Connection error");
close(sock);
return EXIT_FAILURE;
}
char buf[BUFSIZE];
if (send(sock, "hello", 5, 0); /*write may be also used*/ == -1) {
perror("Send error");
close(client_sock);
close(sock);
return EXIT_FAILURE;
}
ssize_t readden = recv(sock, buf, BUFSIZE, 0); /*read may be also used*/
if (readden < 0) {
perror("Receive error");
close(client_sock);
close(sock);
return EXIT_FAILURE;
}
else if (readden == 0)
{
fprintf(stderr, "Client orderly shut down the connection.\n");
}
else /* if (readden > 0) */ {
if (readden < BUFSIZE)
{
fprintf(stderr, "Received less bytes (%zd) then requested (%d).\n",
readden, BUFSIZE);
}
write (STDOUT_FILENO, buf, readden);
}
UDP 伺服器片段
int sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == -1) {
perror("Socket creation error");
return EXIT_FAILURE;
}
if (bind(sock, (struct sockaddr*) &addr, sizeof(addr)) == -1) {
perror("Bind error");
close(sock);
return EXIT_FAILURE;
}
char buf[BUFSIZE];
ssize_t readden = recvfrom(sock, buf, BUFSIZE, 0, &addr, sizeof(addr));
if (readden > 0) {
printf("Client with IP %s sent datagram\n", inet_ntoa(addr.sin_addr));
write (STDOUT_FILENO, buf, readden);
}
sendto(sock, "hello", 5, 0, &addr, sizeof(addr));