Socket Learning

今天试着用了一下socket编程,虽然是以前基本没有接触过的领域,不过因为Unix/Linux基本哲学之一就是“一切皆文件”,一些最基本的操作倒也是很快就上手了。就和普通的文件操作一样,“open -> write/read -> close”。

socket-client是客户端程序,向服务端(socket-server)发送一些数据,服务端按照原样返回。客户端可以指定端口和服务端的IP,服务端可指定端口。例如:

$./socket-server -p 8080
$./socket-client -p 8080 -a 127.0.0.1

即指定让服务端在8080端口监听。客户端使用8080端与127.0.0.1通信。

运行效果如下:

Socket server
Socket client

因为都是基本的操作,所以就直接贴代码了,注释不写应该也没什么问题。

Client

//
//  main.cpp
//  socket-clinet
//
//  Created by Ryza 14/10/31.
//  Copyright (c) 2014年 Ryza. All rights reserved.
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <getopt.h>

#define default_port 327
#define default_server_addr "127.0.0.1"

int main(int argc, const char * argv[]) {
        int sockfd;
        ssize_t recbytes;
        char recv_data[4096],send_data[4096];
        struct sockaddr_in server_addr;
        char * server_address = default_server_addr;
        int port = default_port;
        int ch;
        while(( ch = getopt(argc,argv,"a:p:"))!= -1)
        {
                switch(ch)
                {
                        case 'a': server_address = optarg; break;
                        case 'p': port = atoi(optarg); break;
                        default: printf("unknown optionn");
                }
        }
        memset(&server_addr, 0, sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        server_addr.sin_port = htons(port);
        server_addr.sin_addr.s_addr = inet_addr(server_address);
        while (1) {
                if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
                        perror("socket: ");
                        exit(1);
                }
                if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
                        perror("connect: ");
                        exit(1);
                }
                printf("\m33[1mSent: \m33[0m");
        fgets(send_data, 4096, stdin);
                if( send(sockfd, send_data, strlen(send_data), 0) < 0)
                {
                        perror("send: ");
                        exit(1);
                }
                if(-1 == (recbytes = read(sockfd,recv_data,4096)))
                {
                        perror("read: ");
                        exit(1);
                }
                printf("\m33[1m");
                recv_data[recbytes]='�';
                printf("Recv: \m33[0m%s",recv_data);
                if (strcmp(recv_data, "Goodbye!n") == 0) {
                        break;
                }
                close(sockfd);
        }
        return 0;
}

Server

//
//  main.cpp
//  socket-server
//
//  Created by Ryza 14/10/31.
//  Copyright (c) 2014年 Ryza. All rights reserved.
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define default_port 327

int main(int argc, const char * argv[]) {
        int sockfd, connfd;
        struct sockaddr_in server_addr;
        char recv_data[4096];
        ssize_t recbytes;
        int port = default_port;
        int ch;
        while(( ch = getopt(argc,argv,"a:p:"))!= -1)
        {
                switch(ch)
                {
                        case 'p': port = atoi(optarg); break;
                        default: printf("unknown optionn");
                }
        }
        if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
                perror("socket: ");
                exit(1);
        }
        memset(&server_addr, 0, sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
        server_addr.sin_port = htons(port);
        if( bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1){
                perror("bind: ");
                exit(1);
        }
        if( listen(sockfd, 10) == -1){
                perror("listen: ");
                exit(1);
        }
        printf("\m33[1mlisten on %d. ok to recv msg!n\m33[0m",port);
        while(1){
                struct sockaddr_in client_addr;
                socklen_t socket_len = sizeof(struct sockaddr_in);
                if( (connfd = accept(sockfd, (struct sockaddr *)(&client_addr), &socket_len)) == -1){
                        perror("accept: ");
                        continue;
                }
                if (fork() == 0) {
                        recbytes = recv(connfd, recv_data, 4096, 0);
                        recv_data[recbytes] = '�';
                        if (strcmp(recv_data, "closen") == 0) {
                                write(connfd, "Goodbye!n", 32);
                                printf("\m33[1mGoodbye %s!n\m33[0m",inet_ntoa(client_addr.sin_addr));
                                break;
                        }
                        printf("\m33[1mrecv msg from client[%s]: \m33[0m%s",inet_ntoa(client_addr.sin_addr),recv_data);
                        write(connfd,recv_data,4096);
                        close(connfd);
                        exit(0);
                }
        }
        close(sockfd);
        return 0;
}

One thought on “Socket Learning”

  1. 博主你好,
    我现在iOS设备上socket监听端口遇到了一些问题,我的app是可以保持后台运行的(播放音频),这时候其实socket还在监听,但是后台一段时间后socket就无法监听这个端口了。查了apple的文档说是后台运行要关闭监听,恢复前台再打开,否则资源有可能被系统回收,端口收到的数据将不再传递给app。请问这个有解决办法吗?(让app后台长时间运行时始终能保持监听端口)

Leave a Reply

Your email address will not be published. Required fields are marked *

two + three =