继上篇文章介绍了Ubuntu Linux 24.04 C语言TCP/IP socket编程基础知识,本文将用C语言在Ubuntu Linux 24.04环境下开发一对使用socket进行TCP/IP通讯的Server/Client程序,实现的功能是:
-
当client连上server时,显示连接成功的信息,然后等待client的输入。
-
将client的输入在server端显示。
socket_server.c文件的内容如下:
cpp
/*
编译生成可执行程序(Ubuntu Linux 24.04)
# gcc ./socket_server.c -o socket_server
# ./socket_server
查看防火墙的状态:(国内的云服务器80,443,8080,8443是备案端口,必须备案以后才能从外网访问,注意避免使用)
# ufw status
# ufw allow 8888
查看端口是否被其它程序占用
# sudo apt lsof
# lsof -i:8888
*/
#include <stdio.h> // printf
#include <string.h> // strlen(char*)
#include <unistd.h> // close(int file_descriptor): close socket
#include <sys/socket.h> // socket(), bind(), accept(), etc
#include <netdb.h> // gethostbyname(char* domain_name)
#include <arpa/inet.h> // long inet_addr(char* ip_address) : convert ip string to long int format
#define SERVER_LISTEN_PORT 8888
#define SOCK_BUF_SIZE 10241
#define SOCK_BUF_SIZE1 10240 // subtract 1 for the null terminator at the buf end
#define SOCK_CONN_QUEUE_MAX 3
int main(int argc, char * argv[])
{
int r=0;
int listen_sock, sock;
struct sockaddr_in server_addr, client_addr;
socklen_t addrlen = sizeof(struct sockaddr_in);
int client_count=0; char *client_ip; int client_port;
char buffer[SOCK_BUF_SIZE] = { 0 };
long recv_size=0, send_size=0;
if ((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("create server listen socket failed"); goto fail; }
printf("create server listen socket succeed\n");
server_addr.sin_family = AF_INET; // IPv4
server_addr.sin_addr.s_addr = INADDR_ANY; // 监听所有本地IP地址
server_addr.sin_port = htons(SERVER_LISTEN_PORT);
if (bind(listen_sock, (struct sockaddr*)&server_addr, addrlen) == -1) { perror("server listen socket bind to ip:port failed"); goto fail_close; }
printf("bind server listen socket to port %d succeed\n", SERVER_LISTEN_PORT);
if (listen(listen_sock, SOCK_CONN_QUEUE_MAX) == -1) { perror("server socket start listening failed"); goto fail_close; }
printf("server socket starts listening ...\n");
while((sock = accept(listen_sock, (struct sockaddr*)&client_addr, &addrlen)) > 0)
{
client_count++;
client_ip = inet_ntoa(client_addr.sin_addr); client_port = ntohs(client_addr.sin_port);
printf("%d --------------- \nserver socket accepted a client connection: %s:%d ---------------\n", client_count, client_ip, client_port);
// if(set_socket_options(sock) == -1) goto end_close_client;
while((recv_size = recv(sock, buffer, SOCK_BUF_SIZE1, 0))>0)
{
if(recv_size<0) { printf("receive from client failed\n"); goto end_close_client;}
buffer[recv_size]=0; // set string end
printf("received %ld bytes data: \n%s\n", recv_size, buffer);
}
//send_size = send(sock, hello, strlen(hello), 0); if(send_size<0) { printf("write to client failed\n"); goto end_close_client;}
//printf("Hello message sent\n");
end_close_client: close(sock);
printf("waiting for next client ...\n");
}
close(listen_sock); goto succeed;
fail_close: close(listen_sock); goto fail;
succeed: return r;
fail: r=1; return r;
}
socket_client.c文件的内容如下:
cpp
/*
编译生成可执行程序(Ubuntu Linux 24.04)
# gcc ./socket_client.c -o socket_client
# ./socket_client
*/
#include <stdio.h> // printf
#include <string.h> // strlen(char*)
#include <stdlib.h> // free(*memory)
#include <unistd.h> // close(int file_descriptor): close socket
#include <sys/socket.h> // socket(), bind(), accept(), etc
#include <netdb.h> // gethostbyname(char* domain_name)
#include <arpa/inet.h> // long inet_addr(char* ip_address) : convert ip string to long int format
#define SERVER_LISTEN_PORT 8888
#define SOCK_BUF_SIZE 10241
#define SOCK_BUF_SIZE1 10240 // subtract 1 for the null terminator at the buf end
#define SERVER_DOMAIN_NAME "idealand.space"
#define BUDA_F(p) if(p){ free(p); p=NULL; }
/* 通过域名获取socket可用的ip地址格式,用于连接server socket
hostname: 例如 idealand.space */
struct in_addr * get_sock_addr(char *hostname)
{
printf("resolving %s to IP address...\n" , hostname);
struct hostent *he;
struct in_addr **addr_list; // data in struct in_addr is long int ip
int i;
if ( (he = gethostbyname( hostname ) ) == NULL ) goto fail;
addr_list = (struct in_addr **) he->h_addr_list;
struct in_addr * ip_addr=NULL;
for(i = 0; (ip_addr=addr_list[i]) != NULL; i++)
{
printf("%d: %s\n", i+1 , inet_ntoa(*ip_addr) ); // inet_ntoa convert an IP address in long int format to dotted format
goto succeed; // use the first IP address
}
if(ip_addr==NULL) goto fail;
succeed: return ip_addr;
fail: printf("gethostbyname for %s failed", hostname); return NULL;
}
int main(int argc, char * argv[])
{
int r=0;
struct in_addr * ip_addr=get_sock_addr(SERVER_DOMAIN_NAME);
if(ip_addr==NULL) goto fail;
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET; // IPv4
server_addr.sin_addr = *ip_addr;
server_addr.sin_port = htons(SERVER_LISTEN_PORT);
socklen_t addrlen = sizeof(struct sockaddr_in);
int sock;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("create client socket failed\n"); goto fail; }
printf("create client socket succeed\n");
if (connect(sock , (struct sockaddr *)&server_addr , addrlen) == -1) { perror("connect to server failed\n"); goto fail_close; }
printf("connect to server succeed\n");
char *line = NULL; size_t len = 0; ssize_t read;
while((read = getline(&line, &len, stdin)) > 0)
{
if(send(sock, line, read, 0) <= 0) goto fail_close;
BUDA_F(line);
}
BUDA_F(line);
close(sock); goto succeed;
fail_close: close(sock); goto fail;
succeed: return r;
fail: r=1; return r;
}